diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 27b8f63..7510cc1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -97,6 +97,7 @@ + @@ -135,10 +136,13 @@ + + + + - @@ -185,7 +189,11 @@ + + . */ + +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.database.sqlite.SQLiteDatabase; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.GridView; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.constraintlayout.widget.ConstraintLayout; + +import java.util.ArrayList; +import java.util.List; + +import app.fedilab.nitterizeme.R; +import app.fedilab.nitterizeme.adapters.AppPickerAdapter; +import app.fedilab.nitterizeme.entities.AppPicker; +import app.fedilab.nitterizeme.helpers.Utils; +import app.fedilab.nitterizeme.sqlite.DefaultAppDAO; +import app.fedilab.nitterizeme.sqlite.Sqlite; + +import static app.fedilab.nitterizeme.helpers.Utils.KILL_ACTIVITY; +import static app.fedilab.nitterizeme.helpers.Utils.URL_APP_PICKER; + + +public class AppsPickerActivity extends Activity { + + + private String url; + private String appToUse; + private String appName; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_pickup_app); + if (getIntent() == null) { + finish(); + } + Bundle b = getIntent().getExtras(); + if (b == null) { + finish(); + } + if (b != null) { + url = b.getString(URL_APP_PICKER, null); + } + if (url == null) { + finish(); + } + //At this point we are sure that url is not null + Intent stopMainActivity = new Intent(KILL_ACTIVITY); + sendBroadcast(stopMainActivity); + + Intent delegate = new Intent(Intent.ACTION_VIEW); + delegate.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + delegate.setData(Uri.parse(url)); + + List activities = getPackageManager().queryIntentActivities(delegate, PackageManager.MATCH_DEFAULT_ONLY); + SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + RelativeLayout blank = findViewById(R.id.blank); + blank.setOnClickListener(v -> finish()); + String thisPackageName = getApplicationContext().getPackageName(); + ArrayList packages = new ArrayList<>(); + List appPickers = new ArrayList<>(); + int i = 0; + for (ResolveInfo currentInfo : activities) { + String packageName = currentInfo.activityInfo.packageName; + if (!thisPackageName.equals(packageName) && !packages.contains(packageName)) { + AppPicker appPicker = new AppPicker(); + appPicker.setIcon(currentInfo.activityInfo.loadIcon(getPackageManager())); + appPicker.setName(String.valueOf(currentInfo.loadLabel(getPackageManager()))); + appPicker.setPackageName(packageName); + if (i == 0) { + appPicker.setSelected(true); + appToUse = packageName; + appName = String.valueOf(currentInfo.loadLabel(getPackageManager())); + } + appPickers.add(appPicker); + packages.add(packageName); + i++; + } + + } + String defaultApp = new DefaultAppDAO(AppsPickerActivity.this, db).getDefault(packages); + + TextView urlText = findViewById(R.id.url); + urlText.setText(url); + + if (defaultApp != null) { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + intent.setPackage(defaultApp); + startActivity(intent); + finish(); + } else { + ConstraintLayout app_container = findViewById(R.id.app_container); + app_container.setVisibility(View.VISIBLE); + GridView gridView = findViewById(R.id.app_list); + AppPickerAdapter appPickerAdapter = new AppPickerAdapter(appPickers); + gridView.setAdapter(appPickerAdapter); + gridView.setNumColumns(3); + gridView.setOnItemClickListener((parent, view1, position, id) -> { + for (AppPicker ap : appPickers) { + ap.setSelected(false); + } + appPickers.get(position).setSelected(true); + appToUse = appPickers.get(position).getPackageName(); + appName = appPickers.get(position).getName(); + appPickerAdapter.notifyDataSetChanged(); + }); + + + Button always = findViewById(R.id.always); + Button once = findViewById(R.id.once); + + always.setOnClickListener(v -> { + + boolean isPresent = new DefaultAppDAO(AppsPickerActivity.this, db).isPresent(appToUse); + long val = -1; + if (isPresent) { + ArrayList oldConcurrent = new DefaultAppDAO(AppsPickerActivity.this, db).getConcurrent(appToUse); + ArrayList newConcurrent = Utils.union(oldConcurrent, packages); + new DefaultAppDAO(AppsPickerActivity.this, db).update(appToUse, newConcurrent); + } else { + val = new DefaultAppDAO(AppsPickerActivity.this, db).insert(appToUse, packages); + } + if (val > 0) { + Toast.makeText(AppsPickerActivity.this, getString(R.string.default_app_indication, appName), Toast.LENGTH_LONG).show(); + } + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + intent.setPackage(appToUse); + startActivity(intent); + finish(); + }); + + once.setOnClickListener(v -> { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + intent.setPackage(appToUse); + startActivity(intent); + finish(); + }); + } + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + +} diff --git a/app/src/main/java/app/fedilab/nitterizeme/activities/DefaultAppActivity.java b/app/src/main/java/app/fedilab/nitterizeme/activities/DefaultAppActivity.java new file mode 100644 index 0000000..c71d141 --- /dev/null +++ b/app/src/main/java/app/fedilab/nitterizeme/activities/DefaultAppActivity.java @@ -0,0 +1,90 @@ +package app.fedilab.nitterizeme.activities; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of UntrackMe + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * UntrackMe is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with UntrackMe; if not, + * see . */ + + +import android.database.sqlite.SQLiteDatabase; +import android.os.Bundle; +import android.view.MenuItem; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; + +import app.fedilab.nitterizeme.R; +import app.fedilab.nitterizeme.adapters.DefaultAppAdapter; +import app.fedilab.nitterizeme.entities.DefaultApp; +import app.fedilab.nitterizeme.helpers.Utils; +import app.fedilab.nitterizeme.sqlite.DefaultAppDAO; +import app.fedilab.nitterizeme.sqlite.Sqlite; + + +public class DefaultAppActivity extends AppCompatActivity { + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_default_app); + + + setTitle(R.string.default_apps); + if (getSupportActionBar() != null) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowHomeEnabled(true); + } + + RecyclerView list_apps = findViewById(R.id.list_apps); + final LinearLayoutManager mLayoutManager; + mLayoutManager = new LinearLayoutManager(DefaultAppActivity.this); + list_apps.setLayoutManager(mLayoutManager); + list_apps.setNestedScrollingEnabled(false); + + ArrayList appInfos = getAppInfo(); + DefaultAppAdapter defaultAppAdapter = new DefaultAppAdapter(appInfos); + list_apps.setAdapter(defaultAppAdapter); + } + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + + + /** + * Get default app set inside the application for opening links + * + * @return ArrayList + */ + private ArrayList getAppInfo() { + ArrayList appInfos = new ArrayList<>(); + SQLiteDatabase db = Sqlite.getInstance(getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + ArrayList packageName = new DefaultAppDAO(DefaultAppActivity.this, db).getDefault(); + for (String p : packageName) { + DefaultApp defaultApp = new DefaultApp(); + defaultApp.setApplicationInfo(Utils.getPackageInfo(DefaultAppActivity.this, p).applicationInfo); + appInfos.add(defaultApp); + } + return appInfos; + } + +} diff --git a/app/src/main/java/app/fedilab/nitterizeme/activities/MainActivity.java b/app/src/main/java/app/fedilab/nitterizeme/activities/MainActivity.java index a8bb059..0b7ba79 100644 --- a/app/src/main/java/app/fedilab/nitterizeme/activities/MainActivity.java +++ b/app/src/main/java/app/fedilab/nitterizeme/activities/MainActivity.java @@ -19,6 +19,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Bundle; import android.provider.Settings; @@ -33,11 +35,13 @@ import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.SwitchCompat; import androidx.appcompat.widget.Toolbar; +import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.Group; import com.google.android.material.snackbar.Snackbar; import com.google.android.material.textfield.TextInputEditText; +import java.util.List; import java.util.Objects; import app.fedilab.nitterizeme.R; @@ -88,7 +92,6 @@ public class MainActivity extends AppCompatActivity { Objects.requireNonNull(getSupportActionBar()).setDisplayShowHomeEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true); - SharedPreferences sharedpreferences = getSharedPreferences(APP_PREFS, Context.MODE_PRIVATE); TextView current_instance_nitter = findViewById(R.id.current_instance_nitter); @@ -138,7 +141,6 @@ public class MainActivity extends AppCompatActivity { enable_invidious.setChecked(invidious_enabled); enable_bibliogram.setChecked(bibliogram_enabled); enable_osm.setChecked(osm_enabled); - ImageButton save_instance_nitter = findViewById(R.id.button_save_instance_nitter); ImageButton save_instance_invidious = findViewById(R.id.button_save_instance_invidious); ImageButton save_instance_bibliogram = findViewById(R.id.button_save_instance_bibliogram); @@ -462,6 +464,10 @@ public class MainActivity extends AppCompatActivity { Intent intent = new Intent(MainActivity.this, AboutActivity.class); startActivity(intent); return true; + } else if (id == R.id.action_settings) { + Intent intent = new Intent(MainActivity.this, DefaultAppActivity.class); + startActivity(intent); + return true; } else if (id == android.R.id.home) { finish(); } @@ -504,5 +510,14 @@ public class MainActivity extends AppCompatActivity { bibliogram_instance.setText(bibliogramHost); current_instance_bibliogram.setText(bibliogramHost); } + + List resolveInfos = getPackageManager().queryIntentActivities(new Intent(Intent.ACTION_VIEW, Uri.parse("https://fedilab.app")), PackageManager.MATCH_DEFAULT_ONLY); + String thisPackageName = getApplicationContext().getPackageName(); + ConstraintLayout display_indications = findViewById(R.id.display_indications); + if (resolveInfos.size() == 1 && resolveInfos.get(0).activityInfo.packageName.compareTo(thisPackageName) == 0) { + display_indications.setVisibility(View.VISIBLE); + } else { + display_indications.setVisibility(View.GONE); + } } } diff --git a/app/src/main/java/app/fedilab/nitterizeme/activities/TransformActivity.java b/app/src/main/java/app/fedilab/nitterizeme/activities/TransformActivity.java index ded182c..336856b 100644 --- a/app/src/main/java/app/fedilab/nitterizeme/activities/TransformActivity.java +++ b/app/src/main/java/app/fedilab/nitterizeme/activities/TransformActivity.java @@ -15,18 +15,14 @@ package app.fedilab.nitterizeme.activities; * see . */ import android.app.Activity; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.os.Parcelable; import android.util.Patterns; import android.view.View; import android.widget.Button; @@ -35,7 +31,6 @@ import android.widget.RelativeLayout; import android.widget.TextView; import androidx.appcompat.app.AlertDialog; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; @@ -43,7 +38,6 @@ import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -59,15 +53,16 @@ import static app.fedilab.nitterizeme.activities.CheckAppActivity.shortener_doma import static app.fedilab.nitterizeme.activities.CheckAppActivity.twitter_domains; import static app.fedilab.nitterizeme.activities.CheckAppActivity.youtube_domains; import static app.fedilab.nitterizeme.activities.MainActivity.SET_BIBLIOGRAM_ENABLED; -import static app.fedilab.nitterizeme.activities.MainActivity.SET_EMBEDDED_PLAYER; import static app.fedilab.nitterizeme.activities.MainActivity.SET_INVIDIOUS_ENABLED; import static app.fedilab.nitterizeme.activities.MainActivity.SET_NITTER_ENABLED; import static app.fedilab.nitterizeme.helpers.Utils.KILL_ACTIVITY; +import static app.fedilab.nitterizeme.helpers.Utils.URL_APP_PICKER; import static app.fedilab.nitterizeme.helpers.Utils.ampExtract; import static app.fedilab.nitterizeme.helpers.Utils.bibliogramAccountPattern; import static app.fedilab.nitterizeme.helpers.Utils.bibliogramPostPattern; import static app.fedilab.nitterizeme.helpers.Utils.maps; import static app.fedilab.nitterizeme.helpers.Utils.nitterPattern; +import static app.fedilab.nitterizeme.helpers.Utils.remove_tracking_param; import static app.fedilab.nitterizeme.helpers.Utils.transformUrl; import static app.fedilab.nitterizeme.helpers.Utils.youtubePattern; @@ -116,9 +111,7 @@ public class TransformActivity extends Activity { Intent delegate = new Intent(Intent.ACTION_VIEW); delegate.setData(Uri.parse(notShortnedURLDialog.get(notShortnedURLDialog.size() - 1))); delegate.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - if (delegate.resolveActivity(getPackageManager()) != null) { - startActivity(delegate); - } + forwardToBrowser(delegate); } dialog.dismiss(); finish(); @@ -171,10 +164,7 @@ public class TransformActivity extends Activity { if (transformedURL != null) { delegate.setData(Uri.parse(transformUrl(TransformActivity.this, url))); delegate.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - if (delegate.resolveActivity(getPackageManager()) != null) { - startActivity(delegate); - finish(); - } + forwardToBrowser(delegate); } else { forwardToBrowser(intent); } @@ -190,10 +180,7 @@ public class TransformActivity extends Activity { if (transformedURL != null) { delegate.setData(Uri.parse(transformUrl(TransformActivity.this, url))); delegate.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - if (delegate.resolveActivity(getPackageManager()) != null) { - startActivity(delegate); - finish(); - } + forwardToBrowser(delegate); } else { forwardToBrowser(intent); } @@ -210,10 +197,7 @@ public class TransformActivity extends Activity { if (transformedURL != null) { delegate.setData(Uri.parse(transformUrl(TransformActivity.this, url))); delegate.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - if (delegate.resolveActivity(getPackageManager()) != null) { - startActivity(delegate); - finish(); - } + forwardToBrowser(delegate); } else { forwardToBrowser(intent); } @@ -232,10 +216,7 @@ public class TransformActivity extends Activity { if (transformedURL != null) { delegate.setData(Uri.parse(transformedURL)); delegate.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - if (delegate.resolveActivity(getPackageManager()) != null) { - startActivity(delegate); - finish(); - } + forwardToBrowser(delegate); } else { forwardToBrowser(intent); } @@ -249,10 +230,7 @@ public class TransformActivity extends Activity { if (transformedURL != null) { delegate.setData(Uri.parse(transformUrl(TransformActivity.this, url))); delegate.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - if (delegate.resolveActivity(getPackageManager()) != null) { - startActivity(delegate); - finish(); - } + forwardToBrowser(delegate); } else { forwardToBrowser(intent); } @@ -304,6 +282,10 @@ public class TransformActivity extends Activity { } else { forwardToBrowser(intent); } + } else { + String newUrl = remove_tracking_param(url); + intent.setData(Uri.parse(newUrl)); + forwardToBrowser(intent); } } @@ -327,64 +309,12 @@ public class TransformActivity extends Activity { * @param i original intent */ private void forwardToBrowser(Intent i) { - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_VIEW); - String type = i.getType(); - if (type == null) { - type = "text/html"; - } - intent.setDataAndType(i.getData(), type); - List activities = getPackageManager().queryIntentActivities(intent, 0); - ArrayList targetIntents = new ArrayList<>(); - String thisPackageName = getApplicationContext().getPackageName(); - ArrayList packages = new ArrayList<>(); - for (ResolveInfo currentInfo : activities) { - String packageName = currentInfo.activityInfo.packageName; - if (!thisPackageName.equals(packageName) && !packages.contains(packageName)) { - Intent targetIntent = new Intent(Intent.ACTION_VIEW); - targetIntent.setDataAndType(intent.getData(), intent.getType()); - targetIntent.setPackage(intent.getPackage()); - targetIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - targetIntent.setComponent(new ComponentName(packageName, currentInfo.activityInfo.name)); - targetIntents.add(targetIntent); - packages.add(packageName); - } - } - //NewPipe has to be manually added - if (isNewPipeInstalled() && Arrays.asList(invidious_instances).contains(Objects.requireNonNull(i.getData()).getHost()) && !packages.contains("org.schabi.newpipe")) { - Intent targetIntent = new Intent(Intent.ACTION_VIEW); - targetIntent.setDataAndType(intent.getData(), intent.getType()); - targetIntent.setPackage(intent.getPackage()); - targetIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - targetIntent.setComponent(new ComponentName("org.schabi.newpipe", "org.schabi.newpipe.RouterActivity")); - targetIntents.add(0, targetIntent); - } - SharedPreferences sharedpreferences = getSharedPreferences(MainActivity.APP_PREFS, Context.MODE_PRIVATE); - boolean embedded_player = sharedpreferences.getBoolean(SET_EMBEDDED_PLAYER, false); - - if (Arrays.asList(invidious_instances).contains(Objects.requireNonNull(i.getData()).getHost()) && embedded_player) { - if (!i.getData().toString().contains("videoplayback") && !i.getData().toString().contains("/channel/")) { - Intent intentPlayer = new Intent(TransformActivity.this, WebviewPlayerActivity.class); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - intentPlayer.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - } - intentPlayer.putExtra("url", i.getData().toString()); - startActivity(intentPlayer); - } else { - Intent intentStreamingUrl = new Intent(Utils.RECEIVE_STREAMING_URL); - Bundle b = new Bundle(); - b.putString("streaming_url", i.getData().toString()); - intentStreamingUrl.putExtras(b); - LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intentStreamingUrl); - } - } else if (targetIntents.size() > 0) { - Intent chooserIntent = Intent.createChooser(targetIntents.get(0), getString(R.string.open_with)); - chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{})); - startActivity(chooserIntent); - } + Intent app_picker = new Intent(TransformActivity.this, AppsPickerActivity.class); + Bundle b = new Bundle(); + b.putString(URL_APP_PICKER, i.getDataString()); + app_picker.putExtras(b); + startActivity(app_picker); finish(); } @@ -429,6 +359,13 @@ public class TransformActivity extends Activity { startActivity(sendIntent); return; } + Uri url_r = Uri.parse(url); + String scheme = url_r.getScheme(); + if (scheme == null) { + scheme = "https://"; + } else { + scheme += "://"; + } if (Arrays.asList(twitter_domains).contains(host)) { boolean nitter_enabled = sharedpreferences.getBoolean(SET_NITTER_ENABLED, true); @@ -438,9 +375,9 @@ public class TransformActivity extends Activity { assert host != null; if (host.compareTo("pbs.twimg.com") == 0 || host.compareTo("pic.twitter.com") == 0) { try { - newUrl = "https://" + nitterHost + "/pic/" + URLEncoder.encode(url, "utf-8"); + newUrl = scheme + nitterHost + "/pic/" + URLEncoder.encode(url, "utf-8"); } catch (UnsupportedEncodingException e) { - newUrl = "https://" + nitterHost + "/pic/" + url; + newUrl = scheme + nitterHost + "/pic/" + url; } } else if (url.contains("/search?")) { newUrl = url.replace(host, nitterHost); @@ -448,7 +385,7 @@ public class TransformActivity extends Activity { Matcher matcher = nitterPattern.matcher(url); while (matcher.find()) { final String nitter_directory = matcher.group(2); - newUrl = "https://" + nitterHost + nitter_directory; + newUrl = scheme + nitterHost + nitter_directory; } } } @@ -459,16 +396,16 @@ public class TransformActivity extends Activity { while (matcher.find()) { final String bibliogram_directory = matcher.group(2); String bibliogramHost = sharedpreferences.getString(MainActivity.SET_BIBLIOGRAM_HOST, MainActivity.DEFAULT_BIBLIOGRAM_HOST).toLowerCase(); - newUrl = "https://" + bibliogramHost + bibliogram_directory; + newUrl = scheme + bibliogramHost + bibliogram_directory; } matcher = bibliogramAccountPattern.matcher(url); while (matcher.find()) { final String bibliogram_directory = matcher.group(2); String bibliogramHost = sharedpreferences.getString(MainActivity.SET_BIBLIOGRAM_HOST, MainActivity.DEFAULT_BIBLIOGRAM_HOST).toLowerCase(); if (bibliogram_directory != null && bibliogram_directory.compareTo("privacy") != 0) { - newUrl = "https://" + bibliogramHost + "/u" + bibliogram_directory; + newUrl = scheme + bibliogramHost + "/u" + bibliogram_directory; } else { - newUrl = "https://" + bibliogramHost + bibliogram_directory; + newUrl = scheme + bibliogramHost + bibliogram_directory; } } } @@ -489,14 +426,14 @@ public class TransformActivity extends Activity { zoom = data[2]; } String osmHost = sharedpreferences.getString(MainActivity.SET_OSM_HOST, MainActivity.DEFAULT_OSM_HOST).toLowerCase(); - newUrl = "https://" + osmHost + "/#map=" + zoom + "/" + data[0] + "/" + data[1]; + newUrl = scheme + osmHost + "/#map=" + zoom + "/" + data[0] + "/" + data[1]; } } } } else if (url.contains("/amp/s/")) { Matcher matcher = ampExtract.matcher(url); while (matcher.find()) { - newUrl = "https://" + matcher.group(1); + newUrl = scheme + matcher.group(1); } } else if (Arrays.asList(youtube_domains).contains(host)) { //Youtube URL boolean invidious_enabled = sharedpreferences.getBoolean(SET_INVIDIOUS_ENABLED, true); @@ -506,15 +443,16 @@ public class TransformActivity extends Activity { final String youtubeId = matcher.group(3); String invidiousHost = sharedpreferences.getString(MainActivity.SET_INVIDIOUS_HOST, MainActivity.DEFAULT_INVIDIOUS_HOST).toLowerCase(); if (Objects.requireNonNull(matcher.group(2)).compareTo("youtu.be") == 0) { - newUrl = "https://" + invidiousHost + "/watch?v=" + youtubeId + "&local=true"; + newUrl = scheme + invidiousHost + "/watch?v=" + youtubeId + "&local=true"; } else { - newUrl = "https://" + invidiousHost + "/" + youtubeId + "&local=true"; + newUrl = scheme + invidiousHost + "/" + youtubeId + "&local=true"; } } } } else if (Arrays.asList(shortener_domains).contains(host)) { String finalUrl = url; String finalExtraText = extraText; + String finalScheme = scheme; Thread thread = new Thread() { @Override public void run() { @@ -539,7 +477,7 @@ public class TransformActivity extends Activity { while (matcher.find()) { final String nitter_directory = matcher.group(2); String nitterHost = sharedpreferences.getString(MainActivity.SET_NITTER_HOST, MainActivity.DEFAULT_NITTER_HOST).toLowerCase(); - newUrlFinal = "https://" + nitterHost + nitter_directory; + newUrlFinal = finalScheme + nitterHost + nitter_directory; } String newExtraText = finalExtraText.replaceAll(Pattern.quote(finalUrl), Matcher.quoteReplacement(newUrlFinal)); Intent sendIntent = new Intent(); @@ -554,9 +492,9 @@ public class TransformActivity extends Activity { final String youtubeId = matcher.group(3); String invidiousHost = sharedpreferences.getString(MainActivity.SET_INVIDIOUS_HOST, MainActivity.DEFAULT_INVIDIOUS_HOST).toLowerCase(); if (Objects.requireNonNull(matcher.group(2)).compareTo("youtu.be") == 0) { - newUrlFinal = "https://" + invidiousHost + "/watch?v=" + youtubeId + "&local=true"; + newUrlFinal = finalScheme + invidiousHost + "/watch?v=" + youtubeId + "&local=true"; } else { - newUrlFinal = "https://" + invidiousHost + "/" + youtubeId + "&local=true"; + newUrlFinal = finalScheme + invidiousHost + "/" + youtubeId + "&local=true"; } } String newExtraText = finalExtraText.replaceAll(Pattern.quote(finalUrl), Matcher.quoteReplacement(newUrlFinal)); @@ -581,7 +519,7 @@ public class TransformActivity extends Activity { zoom = data[2]; } String osmHost = sharedpreferences.getString(MainActivity.SET_OSM_HOST, MainActivity.DEFAULT_OSM_HOST).toLowerCase(); - newUrlFinal = "https://" + osmHost + "/#map=" + zoom + "/" + data[0] + "/" + data[1]; + newUrlFinal = finalScheme + osmHost + "/#map=" + zoom + "/" + data[0] + "/" + data[1]; } } String newExtraText = finalExtraText.replaceAll(Pattern.quote(finalUrl), Matcher.quoteReplacement(newUrlFinal)); @@ -602,6 +540,8 @@ public class TransformActivity extends Activity { }; thread.start(); return; + } else { + newUrl = remove_tracking_param(url); } if (newUrl != null) { extraText = extraText.replaceAll(Pattern.quote(url), Matcher.quoteReplacement(newUrl)); @@ -613,17 +553,5 @@ public class TransformActivity extends Activity { startActivity(sendIntent); } - /** - * Check if NewPipe is installed - * - * @return boolean - */ - private boolean isNewPipeInstalled() { - try { - getPackageManager().getPackageInfo("org.schabi.newpipe", 0); - return true; - } catch (PackageManager.NameNotFoundException e) { - return false; - } - } + } diff --git a/app/src/main/java/app/fedilab/nitterizeme/adapters/AppPickerAdapter.java b/app/src/main/java/app/fedilab/nitterizeme/adapters/AppPickerAdapter.java new file mode 100644 index 0000000..441f694 --- /dev/null +++ b/app/src/main/java/app/fedilab/nitterizeme/adapters/AppPickerAdapter.java @@ -0,0 +1,100 @@ +package app.fedilab.nitterizeme.adapters; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of UntrackMe + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * UntrackMe is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with UntrackMe; if not, + * see . */ + +import android.content.res.Resources; +import android.os.Build; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.constraintlayout.widget.ConstraintLayout; + +import java.util.List; + +import app.fedilab.nitterizeme.R; +import app.fedilab.nitterizeme.entities.AppPicker; + +public class AppPickerAdapter extends BaseAdapter { + + private List appPickers; + + public AppPickerAdapter(List appPickers) { + this.appPickers = appPickers; + } + + + @Override + public int getCount() { + return appPickers.size(); + } + + @Override + public AppPicker getItem(int position) { + return appPickers.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + final ViewHolder holder; + AppPicker appPicker = appPickers.get(position); + if (convertView == null) { + LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); + convertView = layoutInflater.inflate(R.layout.drawer_app_picker, parent, false); + holder = new ViewHolder(); + holder.app_icon = convertView.findViewById(R.id.app_icon); + holder.app_name = convertView.findViewById(R.id.app_name); + holder.app_container = convertView.findViewById(R.id.app_container); + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + + try { + holder.app_icon.setImageDrawable(appPicker.getIcon()); + } catch (Resources.NotFoundException e) { + holder.app_icon.setImageResource(R.drawable.ic_android); + } + holder.app_name.setText(appPicker.getName()); + + + if (appPicker.isSelected()) { + holder.app_container.setBackgroundResource(R.drawable.rounded_selector); + } else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + holder.app_container.setBackground(null); + } + } + + return convertView; + + } + + private static class ViewHolder { + ImageView app_icon; + TextView app_name; + ConstraintLayout app_container; + } + +} \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/nitterizeme/adapters/DefaultAppAdapter.java b/app/src/main/java/app/fedilab/nitterizeme/adapters/DefaultAppAdapter.java new file mode 100644 index 0000000..2345ca3 --- /dev/null +++ b/app/src/main/java/app/fedilab/nitterizeme/adapters/DefaultAppAdapter.java @@ -0,0 +1,120 @@ +package app.fedilab.nitterizeme.adapters; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of UntrackMe + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * UntrackMe is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with UntrackMe; if not, + * see . */ + +import android.content.Context; +import android.content.res.Resources; +import android.database.sqlite.SQLiteDatabase; +import android.graphics.drawable.Drawable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.List; + +import app.fedilab.nitterizeme.R; +import app.fedilab.nitterizeme.entities.DefaultApp; +import app.fedilab.nitterizeme.sqlite.DefaultAppDAO; +import app.fedilab.nitterizeme.sqlite.Sqlite; + +public class DefaultAppAdapter extends RecyclerView.Adapter { + + private List defaultApps; + + public DefaultAppAdapter(List packageNames) { + this.defaultApps = packageNames; + } + + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int position) { + Context context = parent.getContext(); + LayoutInflater layoutInflater = LayoutInflater.from(context); + return new ViewHolder(layoutInflater.inflate(R.layout.drawer_default_app, parent, false)); + } + + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) { + DefaultApp defaultApp = defaultApps.get(viewHolder.getAdapterPosition()); + ViewHolder holder = (ViewHolder) viewHolder; + Context context = holder.itemView.getContext(); + if (defaultApp.getApplicationInfo() != null) { + Drawable icon = defaultApp.getApplicationInfo().loadIcon(context.getPackageManager()); + try { + holder.app_icon.setImageDrawable(icon); + } catch (Resources.NotFoundException e) { + holder.app_icon.setImageResource(R.drawable.ic_android); + } + String app_name = context.getPackageManager().getApplicationLabel(defaultApp.getApplicationInfo()).toString(); + String app_package = defaultApp.getApplicationInfo().packageName; + holder.app_name.setText(app_name); + holder.app_package.setText(app_package); + holder.delete.setOnClickListener(v -> { + AlertDialog.Builder confirmDialog = new AlertDialog.Builder(context, R.style.AppThemeDialogDelete); + confirmDialog.setMessage(context.getString(R.string.delete_app_from_default, app_name)); + confirmDialog.setIcon(R.mipmap.ic_launcher); + confirmDialog.setPositiveButton(R.string.delete, (dialog, id) -> { + SQLiteDatabase db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open(); + new DefaultAppDAO(context, db).removeApp(app_package); + defaultApps.remove(defaultApp); + notifyItemRemoved(i); + dialog.dismiss(); + }); + confirmDialog.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss()); + AlertDialog alertDialog = confirmDialog.create(); + alertDialog.show(); + + }); + } else { + holder.app_icon.setImageResource(R.drawable.ic_android); + } + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public int getItemCount() { + return defaultApps.size(); + } + + + static class ViewHolder extends RecyclerView.ViewHolder { + ImageView app_icon, delete; + TextView app_name, app_package; + ConstraintLayout main_container; + + ViewHolder(@NonNull View itemView) { + super(itemView); + app_icon = itemView.findViewById(R.id.app_icon); + delete = itemView.findViewById(R.id.delete); + app_name = itemView.findViewById(R.id.app_name); + app_package = itemView.findViewById(R.id.app_package); + main_container = itemView.findViewById(R.id.main_container); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/nitterizeme/entities/AppPicker.java b/app/src/main/java/app/fedilab/nitterizeme/entities/AppPicker.java new file mode 100644 index 0000000..27dabb9 --- /dev/null +++ b/app/src/main/java/app/fedilab/nitterizeme/entities/AppPicker.java @@ -0,0 +1,57 @@ +package app.fedilab.nitterizeme.entities; + +import android.graphics.drawable.Drawable; + +/* Copyright 2020 Thomas Schneider + * + * This file is a part of UntrackMe + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * UntrackMe is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with UntrackMe; if not, + * see . */ +public class AppPicker { + + private Drawable icon; + private String name; + private String packageName; + private boolean selected = false; + + public Drawable getIcon() { + return icon; + } + + public void setIcon(Drawable icon) { + this.icon = icon; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public boolean isSelected() { + return selected; + } + + public void setSelected(boolean selected) { + this.selected = selected; + } +} diff --git a/app/src/main/java/app/fedilab/nitterizeme/entities/DefaultApp.java b/app/src/main/java/app/fedilab/nitterizeme/entities/DefaultApp.java new file mode 100644 index 0000000..49bded1 --- /dev/null +++ b/app/src/main/java/app/fedilab/nitterizeme/entities/DefaultApp.java @@ -0,0 +1,29 @@ +package app.fedilab.nitterizeme.entities; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of UntrackMe + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * UntrackMe is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with UntrackMe; if not, + * see . */ + + +public class DefaultApp { + + private android.content.pm.ApplicationInfo ApplicationInfo; + + public android.content.pm.ApplicationInfo getApplicationInfo() { + return ApplicationInfo; + } + + public void setApplicationInfo(android.content.pm.ApplicationInfo applicationInfo) { + ApplicationInfo = applicationInfo; + } +} diff --git a/app/src/main/java/app/fedilab/nitterizeme/helpers/Utils.java b/app/src/main/java/app/fedilab/nitterizeme/helpers/Utils.java index 69ff979..313fccc 100644 --- a/app/src/main/java/app/fedilab/nitterizeme/helpers/Utils.java +++ b/app/src/main/java/app/fedilab/nitterizeme/helpers/Utils.java @@ -18,11 +18,14 @@ package app.fedilab.nitterizeme.helpers; import android.app.DownloadManager; import android.content.Context; import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.Environment; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; @@ -31,10 +34,12 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -54,6 +59,7 @@ import static app.fedilab.nitterizeme.activities.MainActivity.SET_NITTER_ENABLED public class Utils { public static final String KILL_ACTIVITY = "kill_activity"; + public static final String URL_APP_PICKER = "url_app_picker"; public static final Pattern youtubePattern = Pattern.compile("(www\\.|m\\.)?(youtube\\.com|youtu\\.be|youtube-nocookie\\.com)/(((?!([\"'<])).)*)"); public static final Pattern nitterPattern = Pattern.compile("(mobile\\.|www\\.)?twitter.com([\\w-/]+)"); public static final Pattern bibliogramPostPattern = Pattern.compile("(m\\.|www\\.)?instagram.com(/p/[\\w-/]+)"); @@ -107,27 +113,44 @@ public class Utils { try { comingURl = urls.get(urls.size() - 1); - if (comingURl.startsWith("http://")) { - comingURl = comingURl.replace("http://", "https://"); - } url = new URL(comingURl); - HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection(); - httpsURLConnection.setRequestProperty("http.keepAlive", "false"); - httpsURLConnection.setInstanceFollowRedirects(false); - httpsURLConnection.setRequestMethod("HEAD"); - if (httpsURLConnection.getResponseCode() == 301) { - Map> map = httpsURLConnection.getHeaderFields(); - for (Map.Entry> entry : map.entrySet()) { - if (entry.toString().toLowerCase().startsWith("location")) { - Matcher matcher = urlPattern.matcher(entry.toString()); - if (matcher.find()) { - newURL = remove_tracking_param(matcher.group(1)); - urls.add(transformUrl(context, newURL)); + if (comingURl.startsWith("https")) { + HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection(); + httpsURLConnection.setRequestProperty("http.keepAlive", "false"); + httpsURLConnection.setInstanceFollowRedirects(false); + httpsURLConnection.setRequestMethod("HEAD"); + if (httpsURLConnection.getResponseCode() == 301) { + Map> map = httpsURLConnection.getHeaderFields(); + for (Map.Entry> entry : map.entrySet()) { + if (entry.toString().toLowerCase().startsWith("location")) { + Matcher matcher = urlPattern.matcher(entry.toString()); + if (matcher.find()) { + newURL = remove_tracking_param(matcher.group(1)); + urls.add(transformUrl(context, newURL)); + } } } } + httpsURLConnection.getInputStream().close(); + } else { + HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); + httpURLConnection.setRequestProperty("http.keepAlive", "false"); + httpURLConnection.setInstanceFollowRedirects(false); + httpURLConnection.setRequestMethod("HEAD"); + if (httpURLConnection.getResponseCode() == 301) { + Map> map = httpURLConnection.getHeaderFields(); + for (Map.Entry> entry : map.entrySet()) { + if (entry.toString().toLowerCase().startsWith("location")) { + Matcher matcher = urlPattern.matcher(entry.toString()); + if (matcher.find()) { + newURL = remove_tracking_param(matcher.group(1)); + urls.add(transformUrl(context, newURL)); + } + } + } + } + httpURLConnection.getInputStream().close(); } - httpsURLConnection.getInputStream().close(); if (newURL != null && newURL.compareTo(comingURl) != 0) { URL redirectURL = new URL(newURL); String host = redirectURL.getHost(); @@ -161,6 +184,14 @@ public class Utils { } catch (MalformedURLException e) { e.printStackTrace(); } + Uri url_r = Uri.parse(url); + String scheme = url_r.getScheme(); + if (scheme == null) { + scheme = "https://"; + } else { + scheme += "://"; + } + if (Arrays.asList(twitter_domains).contains(host)) { boolean nitter_enabled = sharedpreferences.getBoolean(SET_NITTER_ENABLED, true); if (nitter_enabled) { @@ -168,9 +199,9 @@ public class Utils { assert host != null; if (host.compareTo("pbs.twimg.com") == 0 || host.compareTo("pic.twitter.com") == 0) { try { - newUrl = "https://" + nitterHost + "/pic/" + URLEncoder.encode(url, "utf-8"); + newUrl = scheme + nitterHost + "/pic/" + URLEncoder.encode(url, "utf-8"); } catch (UnsupportedEncodingException e) { - newUrl = "https://" + nitterHost + "/pic/" + url; + newUrl = scheme + nitterHost + "/pic/" + url; } } else if (url.contains("/search?")) { newUrl = url.replace(host, nitterHost); @@ -178,7 +209,7 @@ public class Utils { Matcher matcher = nitterPattern.matcher(url); while (matcher.find()) { final String nitter_directory = matcher.group(2); - newUrl = "https://" + nitterHost + nitter_directory; + newUrl = scheme + nitterHost + nitter_directory; } } return newUrl; @@ -192,16 +223,16 @@ public class Utils { while (matcher.find()) { final String bibliogram_directory = matcher.group(2); String bibliogramHost = sharedpreferences.getString(MainActivity.SET_BIBLIOGRAM_HOST, MainActivity.DEFAULT_BIBLIOGRAM_HOST).toLowerCase(); - newUrl = "https://" + bibliogramHost + bibliogram_directory; + newUrl = scheme + bibliogramHost + bibliogram_directory; } matcher = bibliogramAccountPattern.matcher(url); while (matcher.find()) { final String bibliogram_directory = matcher.group(2); String bibliogramHost = sharedpreferences.getString(MainActivity.SET_BIBLIOGRAM_HOST, MainActivity.DEFAULT_BIBLIOGRAM_HOST).toLowerCase(); if (bibliogram_directory != null && bibliogram_directory.compareTo("privacy") != 0) { - newUrl = "https://" + bibliogramHost + "/u" + bibliogram_directory; + newUrl = scheme + bibliogramHost + "/u" + bibliogram_directory; } else { - newUrl = "https://" + bibliogramHost + bibliogram_directory; + newUrl = scheme + bibliogramHost + bibliogram_directory; } } return newUrl; @@ -228,7 +259,7 @@ public class Utils { String osmHost = sharedpreferences.getString(MainActivity.SET_OSM_HOST, MainActivity.DEFAULT_OSM_HOST).toLowerCase(); boolean geo_uri_enabled = sharedpreferences.getBoolean(MainActivity.SET_GEO_URIS, false); if (!geo_uri_enabled) { - newUrl = "https://" + osmHost + "/#map=" + zoom + "/" + data[0] + "/" + data[1]; + newUrl = scheme + osmHost + "/#map=" + zoom + "/" + data[0] + "/" + data[1]; } else { newUrl = "geo:0,0?q=" + data[0] + "," + data[1] + ",z=" + zoom; } @@ -253,9 +284,9 @@ public class Utils { final String youtubeId = matcher.group(3); String invidiousHost = sharedpreferences.getString(MainActivity.SET_INVIDIOUS_HOST, MainActivity.DEFAULT_INVIDIOUS_HOST).toLowerCase(); if (Objects.requireNonNull(matcher.group(2)).compareTo("youtu.be") == 0) { - newUrl = "https://" + invidiousHost + "/watch?v=" + youtubeId + "&local=true"; + newUrl = scheme + invidiousHost + "/watch?v=" + youtubeId + "&local=true"; } else { - newUrl = "https://" + invidiousHost + "/" + youtubeId + "&local=true"; + newUrl = scheme + invidiousHost + "/" + youtubeId + "&local=true"; } } return newUrl; @@ -291,7 +322,7 @@ public class Utils { * @param url String URL * @return cleaned URL String */ - private static String remove_tracking_param(String url) { + public static String remove_tracking_param(String url) { if (url != null) { for (String utm : UTM_PARAMS) { url = url.replaceAll("&" + utm + "=[0-9a-zA-Z._-]*", ""); @@ -336,4 +367,93 @@ public class Utils { e.printStackTrace(); } } + + + /** + * Check if an app is installed + * + * @return boolean + */ + @SuppressWarnings("unused") + public static boolean isAppInstalled(Context context, String packageName) { + try { + context.getPackageManager().getPackageInfo(packageName, 0); + return true; + } catch (PackageManager.NameNotFoundException e) { + return false; + } + } + + /** + * Get PackageInfo for an app + * + * @return PackageInfo + */ + @SuppressWarnings("unused") + public static PackageInfo getPackageInfo(Context context, String packageName) { + PackageInfo packageInfo = null; + try { + packageInfo = context.getPackageManager().getPackageInfo(packageName, 0); + } catch (Exception ignored) { + } + return packageInfo; + } + + + /** + * Convert an ArrayList to a string using coma + * + * @param arrayList ArrayList + * @return String + */ + public static String arrayToString(ArrayList arrayList) { + if (arrayList == null || arrayList.size() == 0) { + return null; + } + StringBuilder result = new StringBuilder(); + for (String item : arrayList) { + result.append(item).append(","); + } + return result.substring(0, result.length() - 1); + } + + /** + * Convert an ArrayList to a string using coma + * + * @param arrayList ArrayList + * @return String + */ + public static String arrayToStringQuery(ArrayList arrayList) { + if (arrayList == null || arrayList.size() == 0) { + return null; + } + StringBuilder result = new StringBuilder(); + for (String item : arrayList) { + result.append("'").append(item).append("'").append(","); + } + return result.substring(0, result.length() - 1); + } + + /** + * Convert String items to Array + * + * @param items String + * @return ArrayList + */ + public static ArrayList stringToArray(String items) { + if (items == null) { + return null; + } + String[] result = items.split(","); + return new ArrayList<>(Arrays.asList(result)); + } + + + public static ArrayList union(ArrayList list1, ArrayList list2) { + Set set = new HashSet<>(); + set.addAll(list1); + set.addAll(list2); + return new ArrayList<>(set); + } + } diff --git a/app/src/main/java/app/fedilab/nitterizeme/sqlite/DefaultAppDAO.java b/app/src/main/java/app/fedilab/nitterizeme/sqlite/DefaultAppDAO.java new file mode 100644 index 0000000..7121bef --- /dev/null +++ b/app/src/main/java/app/fedilab/nitterizeme/sqlite/DefaultAppDAO.java @@ -0,0 +1,154 @@ +package app.fedilab.nitterizeme.sqlite; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of UntrackMe + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * UntrackMe is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with UntrackMe; if not, + * see . */ + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; + +import java.util.ArrayList; + +import app.fedilab.nitterizeme.helpers.Utils; + +public class DefaultAppDAO { + + public Context context; + private SQLiteDatabase db; + + + public DefaultAppDAO(Context context, SQLiteDatabase db) { + this.context = context; + this.db = db; + } + + public long insert(String packageName, ArrayList concurrentPackages) { + ContentValues values = new ContentValues(); + values.put(Sqlite.COL_DEFAULT_PACKAGE, packageName.trim()); + concurrentPackages.remove(packageName); + values.put(Sqlite.COL_CONCURRENT_PACKAGES, Utils.arrayToString(concurrentPackages)); + try { + return db.insert(Sqlite.TABLE_DEFAULT_APPS, null, values); + } catch (Exception ignored) { + return -1; + } + } + + public void update(String packageName, ArrayList concurrentPackages) { + ContentValues values = new ContentValues(); + values.put(Sqlite.COL_CONCURRENT_PACKAGES, Utils.arrayToString(concurrentPackages)); + try { + db.update(Sqlite.TABLE_DEFAULT_APPS, values, Sqlite.COL_DEFAULT_PACKAGE + " = ? ", new String[]{packageName}); + } catch (Exception ignored) { + } + } + + public int removeApp(String packageName) { + return db.delete(Sqlite.TABLE_DEFAULT_APPS, Sqlite.COL_DEFAULT_PACKAGE + " = \"" + packageName + "\"", null); + } + + public int removeAll() { + return db.delete(Sqlite.TABLE_DEFAULT_APPS, null, null); + } + + public ArrayList getConcurrent(String packageName) { + try { + Cursor c = db.query(Sqlite.TABLE_DEFAULT_APPS, null, Sqlite.COL_DEFAULT_PACKAGE + " = '" + packageName + "'", null, null, null, null, null); + return cursorGetConcurrent(c); + } catch (Exception e) { + return null; + } + } + + public ArrayList getDefault() { + try { + Cursor c = db.query(Sqlite.TABLE_DEFAULT_APPS, null, null, null, null, null, null, null); + return cursorGetDefaults(c); + } catch (Exception e) { + return null; + } + } + + public String getDefault(ArrayList packageNames) { + try { + Cursor c = db.query(Sqlite.TABLE_DEFAULT_APPS, null, Sqlite.COL_DEFAULT_PACKAGE + " IN ( " + Utils.arrayToStringQuery(packageNames) + ")", null, null, null, null, null); + return getBestMatchIfExists(c, packageNames); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public boolean isPresent(String packageName) { + Cursor mCount = db.rawQuery("select count(*) from " + Sqlite.TABLE_DEFAULT_APPS + + " where " + Sqlite.COL_DEFAULT_PACKAGE + " = '" + packageName + "'", null); + mCount.moveToFirst(); + int count = mCount.getInt(0); + mCount.close(); + return count > 0; + } + + private ArrayList cursorGetConcurrent(Cursor c) { + if (c.getCount() == 0) { + c.close(); + return null; + } + ArrayList items = null; + if (c.moveToFirst()) { + String concurrentStr = c.getString(c.getColumnIndex(Sqlite.COL_CONCURRENT_PACKAGES)); + items = Utils.stringToArray(concurrentStr); + } + c.close(); + return items; + } + + + private ArrayList cursorGetDefaults(Cursor c) { + if (c.getCount() == 0) { + c.close(); + return null; + } + ArrayList items = new ArrayList<>(); + while (c.moveToNext()) { + String packageName = c.getString(c.getColumnIndex(Sqlite.COL_DEFAULT_PACKAGE)); + items.add(packageName); + } + c.close(); + return items; + } + + + private String getBestMatchIfExists(Cursor c, ArrayList allPackages) { + if (c.getCount() == 0) { + c.close(); + return null; + } + ArrayList concurrent = new ArrayList<>(); + while (c.moveToNext()) { + String packageName = c.getString(c.getColumnIndex(Sqlite.COL_CONCURRENT_PACKAGES)); + concurrent.addAll(Utils.stringToArray(packageName)); + } + for (String conc : concurrent) { + allPackages.remove(conc); + } + c.close(); + //Items will only returns concurrent for default apps. + //The winner will be the one not in concurrent + if (allPackages.size() == 1) { + return allPackages.get(0); + } else return null; + } + +} diff --git a/app/src/main/java/app/fedilab/nitterizeme/sqlite/Sqlite.java b/app/src/main/java/app/fedilab/nitterizeme/sqlite/Sqlite.java new file mode 100644 index 0000000..4cccaa1 --- /dev/null +++ b/app/src/main/java/app/fedilab/nitterizeme/sqlite/Sqlite.java @@ -0,0 +1,67 @@ +package app.fedilab.nitterizeme.sqlite; +/* Copyright 2020 Thomas Schneider + * + * This file is a part of UntrackMe + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * UntrackMe is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with UntrackMe; if not, + * see . */ + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +public class Sqlite extends SQLiteOpenHelper { + + public static final int DB_VERSION = 1; + public static final String DB_NAME = "untrackme_db"; + static final String TABLE_DEFAULT_APPS = "DEFAULT_APPS"; + static final String COL_DEFAULT_PACKAGE = "DEFAULT_PACKAGE"; + static final String COL_CONCURRENT_PACKAGES = "CONCURRENT_PACKAGES"; + private static final String COL_ID = "ID"; + private static final String CREATE_TABLE_DEFAULT_APPS = "CREATE TABLE " + TABLE_DEFAULT_APPS + " (" + + COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + COL_DEFAULT_PACKAGE + " TEXT NOT NULL UNIQUE, " + COL_CONCURRENT_PACKAGES + " TEXT)"; + private static SQLiteDatabase db; + private static Sqlite sInstance; + + + private Sqlite(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { + super(context, name, factory, version); + } + + public static synchronized Sqlite getInstance(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { + if (sInstance == null) { + sInstance = new Sqlite(context, name, factory, version); + } + return sInstance; + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(CREATE_TABLE_DEFAULT_APPS); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + + } + + public SQLiteDatabase open() { + db = getWritableDatabase(); + return db; + } + + public void close() { + if (db != null && db.isOpen()) { + db.close(); + } + } +} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 1f6bb29..0000000 --- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_app_logo.xml b/app/src/main/res/drawable/ic_app_logo.xml new file mode 100644 index 0000000..04ee601 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_logo.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml new file mode 100644 index 0000000..3760de2 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/img1.jpg b/app/src/main/res/drawable/img1.jpg new file mode 100755 index 0000000..080f825 Binary files /dev/null and b/app/src/main/res/drawable/img1.jpg differ diff --git a/app/src/main/res/drawable/img2.jpg b/app/src/main/res/drawable/img2.jpg new file mode 100755 index 0000000..6867afa Binary files /dev/null and b/app/src/main/res/drawable/img2.jpg differ diff --git a/app/src/main/res/drawable/img3.jpg b/app/src/main/res/drawable/img3.jpg new file mode 100755 index 0000000..a3d3bf7 Binary files /dev/null and b/app/src/main/res/drawable/img3.jpg differ diff --git a/app/src/main/res/drawable/rounded_error.xml b/app/src/main/res/drawable/rounded_error.xml new file mode 100644 index 0000000..4b4c173 --- /dev/null +++ b/app/src/main/res/drawable/rounded_error.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_selector.xml b/app/src/main/res/drawable/rounded_selector.xml new file mode 100644 index 0000000..4527ef3 --- /dev/null +++ b/app/src/main/res/drawable/rounded_selector.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_default_app.xml b/app/src/main/res/layout/activity_default_app.xml new file mode 100644 index 0000000..a10f482 --- /dev/null +++ b/app/src/main/res/layout/activity_default_app.xml @@ -0,0 +1,29 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_pickup_app.xml b/app/src/main/res/layout/activity_pickup_app.xml new file mode 100644 index 0000000..5e91a63 --- /dev/null +++ b/app/src/main/res/layout/activity_pickup_app.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + +