...
 
Commits (17)
......@@ -11,17 +11,21 @@
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<application
android:name=".AppManager"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:name=".AppManager"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/AppTheme">
<activity
android:name=".activities.OneClickOpsActivity"
android:exported="false"
android:label="@string/one_click_ops" />
<activity
android:name=".activities.RunningAppsActivity"
android:label="@string/running_apps"
android:exported="false" />
android:exported="false"
android:label="@string/running_apps" />
<activity
android:name=".activities.SettingsActivity"
android:exported="false" />
......@@ -30,14 +34,25 @@
android:exported="false" />
<activity
android:name=".activities.AppUsageActivity"
android:permission="android.permission.PACKAGE_USAGE_STATS"
android:exported="false" />
android:exported="false"
android:permission="android.permission.PACKAGE_USAGE_STATS" />
<activity
android:name=".activities.ClassViewerActivity"
android:exported="false" />
<activity
android:name=".activities.ClassListingActivity"
android:exported="false" />
android:exported="true"
android:label="@string/exodus">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
</activity>
<activity
android:name=".activities.MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
......@@ -50,19 +65,36 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activities.AppInfoActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/app_info"
android:exported="false" />
<activity
android:name=".activities.AppDetailsActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="false" />
android:exported="true"
android:label="@string/app_info" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
</activity>
<activity
android:name=".activities.ManifestViewerActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="false" />
android:exported="true"
android:label="@string/manifest_viewer">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
......@@ -74,4 +106,4 @@
android:resource="@xml/provider_paths" />
</provider>
</application>
</manifest>
</manifest>
\ No newline at end of file
<h5>v2.5.9 (315):</h5>
<ul>
<li>&nbsp;<font color="#09868B">[Feature]</font> Merged App Info as a single tab in App Details</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added option to reset all app ops</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added option to revoke all dangerous app ops/permissions</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Highlight trackers in the component tabs</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added option to save manifest and class dump</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added the ability to grant/revoke development permissions</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added sorting options for components, app ops and uses permissions tabs</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added sort by wifi usage in the App Usage window</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added launch button in the App Info tab</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added never ask option to usage status prompt</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added long click to select apps in the main window</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added changelog within the app</li>
<li>&nbsp;<font color="red">[Fix]</font> Click to select apps during selection mode</li>
<li>&nbsp;<font color="red">[Fix]</font> Improved component blocker</li>
<li>&nbsp;<font color="red">[Fix]</font> Improved manifest loading for large apps</li>
<li>&nbsp;<font color="red">[Fix]</font> Improved tab loading performance</li>
<li>&nbsp;<font color="red">[Fix]</font> Fixed app ops checking and custom app ops for some devices</li>
<li>&nbsp;<font color="red">[Fix]</font> Disabled activity opening for disabled activities</li>
<li>&nbsp;<font color="red">[Fix]</font> Get real activity name for activities that use activity-alias</li>
<li>&nbsp;<font color="red">[Fix]</font> Fixed background colors</li>
<li>&nbsp;<font color="red">[Fix]</font> Fixed crashing when loading the services tab for non-root users</li>
<li>&nbsp;<font color="red">[Fix]</font> Fixed back button for class viewer which was not working</li>
<li>&nbsp;<font color="red">[Fix]</font> Changed block icon's colour to accent colour</li>
<li>&nbsp;<font color="red">[Fix]</font> Removed translation until the app is complete</li>
<li>&nbsp;<font color="red">[Fix]</font> Made links in the credit section clickable</li>
<li>&nbsp;<font color="red">[Fix]</font> Fixed various memory leaks</li>
</ul><br/>
<h5>v2.5.8 (289):</h5>
<ul>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added import/export capabilities for blocking rules</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added ability to select themes (night/day)</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added mode, duration, accept time, reject time for app ops</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Highlight running services</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Highlight disabled components not disabled within App Manager</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added swipe to refresh in the App Usage window</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added screen time percentage with indicator</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Separate instructions and about pages with fullscreen dialog for both</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Rounded overflow menu (still incomplete)</li>
<li>&nbsp;<font color="red">[Fix]</font> Fixed various device/SDK specific app ops issues</li>
<li>&nbsp;<font color="red">[Fix]</font> Stability improvements of the entire apps</li>
<li>&nbsp;<font color="red">[Fix]</font> Added <tt>ACCESS_NETWORK_STATE</tt> permission to support older operating systems</li>
<li>&nbsp;<font color="red">[Fix]</font> Fixed deleting all IFW rules when selecting apply global rules</li>
<li>&nbsp;<font color="red">[Fix]</font> Fixed various search issues</li>
</ul><br/>
<h5>v2.5.7 (265):</h5>
<ul>
<li>&nbsp;<font color="#09868B">[Feature]</font> Initial support for ADB over TCP (port 5555) for non-root users</li>
<li>&nbsp;<font color="red">[Fix]</font> Fixed importing rules from Watt and Blocker</li>
<li>&nbsp;<font color="red">[Fix]</font> Display Aurora Droid in App Info window as a first priority over F-Droid</li>
<li>&nbsp;<font color="red">[Fix]</font> Improved performance for component blocking</li>
<li>&nbsp;<font color="red">[Fix]</font> Fixed app op mode detection issue</li>
</ul>
<p>
<b>For root users:</b> If you've skipped v2.5.6, you may need to apply all rules globally in Settings in order for them to work.
</p><br/>
<h5>v2.5.6 (233):</h5>
<ul>
<li>&nbsp;<font color="#09868B">[Feature]</font> Batch operations in the main window: clear app data, disable run in background, disable/kill/uninstall apps (click on the app icon to select)</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Full support of Blocker's exported files which was broken due to a bug on Blocker app</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Reimplementation of blocking activities, receivers, services and providers</li>
<li>&nbsp;<font color="red">[Fix]</font> Removed ConstraintLayout dependency therefore a potential decrease in app size</li>
<li>&nbsp;<font color="red">[Fix]</font> Fixed duplicate app usage warning in the App Info window</li>
<li>&nbsp;<font color="red">[Fix]</font> Fixed crash when an app icon is not found in App Details window</li>
</ul>
<p>
<b>Note for root users:</b> In order to ensure that the previous blocking rules are preserved with the new blocking implementation, this update reads from the previous rules consequently increasing the loading time in the main window. This feature will be removed in the next release but can still be simulated by applying global rules in settings.
</p><br/>
<h5>v2.5.5 (215):</h5>
<ul>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added running apps/process viewer (requires root)</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added usage details viewer</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Added apk updater and aurora store support</li>
<li>&nbsp;<font color="#09868B">[Feature]</font> Save modified values of app ops and permissions to the disk (on progress)</li>
<li>&nbsp;<font color="red">[Fix]</font> Uninstall support for non-root users</li>
<li>&nbsp;<font color="red">[Fix]</font> Restructure app usage</li>
<li>&nbsp;<font color="red">[Fix]</font> Added more clarity as well as improve performance in the app details window</li>
</ul>
......@@ -61,6 +61,8 @@ public class IOUtils {
output.write(buffer, 0, n);
count += n;
}
input.close();
if (output != null) output.close();
return count;
}
/**
......
......@@ -41,7 +41,7 @@ public class UriUtils {
@Nullable
public static String pathUriCache(@NonNull Context context, Uri uri, String nCache) {
File f = new File(context.getCacheDir(), nCache);
File f = new File(context.getFilesDir(), nCache);
try {
FileOutputStream fos = new FileOutputStream(f);
InputStream is = context.getContentResolver().openInputStream(uri);
......
......@@ -2,8 +2,9 @@ package io.github.muntashirakon.AppManager.activities;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ApplicationInfo;
import android.content.res.TypedArray;
import android.net.Uri;
import android.os.Bundle;
import android.view.Gravity;
import android.view.Menu;
......@@ -14,19 +15,22 @@ import android.widget.Toast;
import com.google.android.material.tabs.TabLayout;
import java.io.IOException;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.menu.MenuBuilder;
import androidx.appcompat.widget.SearchView;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.lifecycle.ViewModelProvider;
import androidx.viewpager.widget.ViewPager;
import io.github.muntashirakon.AppManager.AppManager;
import io.github.muntashirakon.AppManager.R;
import io.github.muntashirakon.AppManager.fragments.AppDetailsFragment;
import io.github.muntashirakon.AppManager.fragments.AppInfoFragment;
import io.github.muntashirakon.AppManager.utils.Utils;
import io.github.muntashirakon.AppManager.viewmodels.AppDetailsViewModel;
......@@ -36,61 +40,87 @@ public class AppDetailsActivity extends AppCompatActivity {
public AppDetailsViewModel model;
public SearchView searchView;
private String mPackageName;
private TypedArray mTabTitleIds;
private AppDetailsFragment[] fragments;
private Fragment[] fragments;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_app_details);
setSupportActionBar(findViewById(R.id.toolbar));
mPackageName = getIntent().getStringExtra(AppInfoActivity.EXTRA_PACKAGE_NAME);
if (mPackageName == null) {
Intent intent = getIntent();
// Check for package name
final String packageName = intent.getStringExtra(AppDetailsActivity.EXTRA_PACKAGE_NAME);
final Uri apkUri = intent.getData();
// Initialize tabs
mTabTitleIds = getResources().obtainTypedArray(R.array.TAB_TITLES);
fragments = new Fragment[mTabTitleIds.length()];
if (packageName == null && apkUri == null) {
Toast.makeText(this, getString(R.string.empty_package_name), Toast.LENGTH_LONG).show();
finish();
return;
}
// Set title
try {
setTitle(getPackageManager().getApplicationInfo(mPackageName, 0).loadLabel(getPackageManager()).toString());
} catch (PackageManager.NameNotFoundException ignored) {
finish();
return;
}
// Get model
model = ViewModelProvider.AndroidViewModelFactory.getInstance(AppManager.getInstance()).create(AppDetailsViewModel.class);
model.setPackageName(mPackageName);
// Initialize tabs
mTabTitleIds = getResources().obtainTypedArray(R.array.TAB_TITLES);
FragmentManager fragmentManager = getSupportFragmentManager();
ViewPager viewPager = findViewById(R.id.pager);
viewPager.setAdapter(new AppDetailsFragmentPagerAdapter(fragmentManager));
fragments = new AppDetailsFragment[mTabTitleIds.length()];
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
searchView = new SearchView(actionBar.getThemedContext());
actionBar.setDisplayShowCustomEnabled(true);
searchView.setQueryHint(getString(R.string.search));
((ImageView) searchView.findViewById(androidx.appcompat.R.id.search_button))
.setColorFilter(Utils.getThemeColor(this, android.R.attr.colorAccent));
((ImageView) searchView.findViewById(androidx.appcompat.R.id.search_close_btn))
.setColorFilter(Utils.getThemeColor(this, android.R.attr.colorAccent));
ActionBar.LayoutParams layoutParams = new ActionBar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.gravity = Gravity.END;
actionBar.setCustomView(searchView, layoutParams);
}
TabLayout tabLayout = findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(viewPager);
model = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()).create(AppDetailsViewModel.class);
new Thread(() -> {
if (packageName != null) model.setPackageName(packageName);
else {
try {
model.setPackageUri(apkUri);
} catch (IOException e) {
e.printStackTrace();
runOnUiThread(() -> {
Toast.makeText(this, getString(R.string.empty_package_name), Toast.LENGTH_LONG).show();
finish();
});
return;
}
}
ApplicationInfo applicationInfo = model.getPackageInfo().applicationInfo;
runOnUiThread(() -> {
// Set title
setTitle(applicationInfo.loadLabel(getPackageManager()));
FragmentManager fragmentManager = getSupportFragmentManager();
ViewPager viewPager = findViewById(R.id.pager);
viewPager.setAdapter(new AppDetailsFragmentPagerAdapter(fragmentManager));
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
searchView = new SearchView(actionBar.getThemedContext());
actionBar.setDisplayShowCustomEnabled(true);
searchView.setQueryHint(getString(R.string.search));
((ImageView) searchView.findViewById(androidx.appcompat.R.id.search_button))
.setColorFilter(Utils.getThemeColor(this, android.R.attr.colorAccent));
((ImageView) searchView.findViewById(androidx.appcompat.R.id.search_close_btn))
.setColorFilter(Utils.getThemeColor(this, android.R.attr.colorAccent));
ActionBar.LayoutParams layoutParams = new ActionBar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.gravity = Gravity.END;
actionBar.setCustomView(searchView, layoutParams);
}
TabLayout tabLayout = findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(viewPager);
});
}).start();
// Check for the existence of package
model.getIsPackageExist().observe(this, isPackageExist -> {
if (!isPackageExist) {
Toast.makeText(this, packageName + ": " + getString(R.string.app_not_installed), Toast.LENGTH_LONG).show();
finish();
}
});
}
@Override
protected void onDestroy() {
model.onCleared();
super.onDestroy();
}
@SuppressLint("RestrictedApi")
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_app_details_actions, menu);
if (menu instanceof MenuBuilder) {
((MenuBuilder) menu).setOptionalIconsVisible(true);
}
......@@ -103,10 +133,6 @@ public class AppDetailsActivity extends AppCompatActivity {
if (id == android.R.id.home) {
finish();
return true;
} else if (id == R.id.action_app_info) {
Intent appInfoIntent = new Intent(this, AppInfoActivity.class);
appInfoIntent.putExtra(AppInfoActivity.EXTRA_PACKAGE_NAME, mPackageName);
startActivity(appInfoIntent);
}
return super.onOptionsItemSelected(item);
}
......@@ -119,8 +145,11 @@ public class AppDetailsActivity extends AppCompatActivity {
@NonNull
@Override
public AppDetailsFragment getItem(int position) {
if (fragments[position] == null) fragments[position] = new AppDetailsFragment(position);
public Fragment getItem(int position) {
if (fragments[position] == null) {
if (position == 0) fragments[position] = new AppInfoFragment();
else fragments[position] = new AppDetailsFragment(position);
}
return fragments[position];
}
......
package io.github.muntashirakon.AppManager.activities;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import io.github.muntashirakon.AppManager.R;
import io.github.muntashirakon.AppManager.utils.ListItemCreator;
import android.os.Bundle;
import android.view.MenuItem;
import com.google.android.material.progressindicator.ProgressIndicator;
public class OneClickOpsActivity extends AppCompatActivity {
private ListItemCreator mItemCreator;
private ProgressIndicator mProgressIndicator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one_click_ops);
setSupportActionBar(findViewById(R.id.toolbar));
mItemCreator = new ListItemCreator(this, R.id.container);
mProgressIndicator = findViewById(R.id.progress_linear);
setItems();
}
private void setItems() {
mItemCreator.addItemWithTitle("Not yet implemented");
mProgressIndicator.hide();
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}
\ No newline at end of file
......@@ -105,7 +105,7 @@ public class RunningAppsActivity extends AppCompatActivity implements SearchView
mAdapter = new RunningAppsAdapter(this);
mListView.setAdapter(mAdapter);
mConstraint = null;
enableKillForSystem = (boolean) AppPref.get(AppPref.PREF_ENABLE_KILL_FOR_SYSTEM, AppPref.TYPE_BOOLEAN);
enableKillForSystem = (boolean) AppPref.get(AppPref.PrefKey.PREF_ENABLE_KILL_FOR_SYSTEM_BOOL);
refresh();
}
......@@ -127,7 +127,7 @@ public class RunningAppsActivity extends AppCompatActivity implements SearchView
return true;
case R.id.action_toggle_kill:
enableKillForSystem = !enableKillForSystem;
AppPref.getInstance().setPref(AppPref.PREF_ENABLE_KILL_FOR_SYSTEM, enableKillForSystem);
AppPref.getInstance().setPref(AppPref.PrefKey.PREF_ENABLE_KILL_FOR_SYSTEM_BOOL, enableKillForSystem);
refresh();
return true;
}
......
......@@ -4,6 +4,7 @@ import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.text.Spanned;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
......@@ -18,11 +19,14 @@ import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.text.HtmlCompat;
import io.github.muntashirakon.AppManager.BuildConfig;
import io.github.muntashirakon.AppManager.R;
import io.github.muntashirakon.AppManager.storage.compontents.ComponentsBlocker;
import io.github.muntashirakon.AppManager.fragments.ImportExportDialogFragment;
import io.github.muntashirakon.AppManager.types.FullscreenDialog;
import io.github.muntashirakon.AppManager.utils.AppPref;
import io.github.muntashirakon.AppManager.utils.Utils;
public class SettingsActivity extends AppCompatActivity {
private static List<Integer> themeConst = Arrays.asList(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM, AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY, AppCompatDelegate.MODE_NIGHT_NO, AppCompatDelegate.MODE_NIGHT_YES);
......@@ -46,10 +50,10 @@ public class SettingsActivity extends AppCompatActivity {
final TextView appThemeMsg = findViewById(R.id.app_theme_msg);
// Read pref
Boolean rootEnabled = (Boolean) appPref.getPref(AppPref.PREF_ROOT_MODE_ENABLED, AppPref.TYPE_BOOLEAN);
Boolean blockingEnabled = (Boolean) appPref.getPref(AppPref.PREF_GLOBAL_BLOCKING_ENABLED, AppPref.TYPE_BOOLEAN);
Boolean usageEnabled = (Boolean) appPref.getPref(AppPref.PREF_USAGE_ACCESS_ENABLED, AppPref.TYPE_BOOLEAN);
currentTheme = (int) appPref.getPref(AppPref.PREF_APP_THEME, AppPref.TYPE_INTEGER);
boolean rootEnabled = appPref.getBoolean(AppPref.PrefKey.PREF_ROOT_MODE_ENABLED_BOOL);
boolean blockingEnabled = appPref.getBoolean(AppPref.PrefKey.PREF_GLOBAL_BLOCKING_ENABLED_BOOL);
boolean usageEnabled = appPref.getBoolean(AppPref.PrefKey.PREF_USAGE_ACCESS_ENABLED_BOOL);
currentTheme = appPref.getInt(AppPref.PrefKey.PREF_APP_THEME_INT);
// Set changed values
rootSwitcher.setChecked(rootEnabled);
......@@ -66,7 +70,7 @@ public class SettingsActivity extends AppCompatActivity {
.setSingleChoiceItems(themes, themeConst.indexOf(currentTheme),
(dialog, which) -> currentTheme = themeConst.get(which))
.setPositiveButton(R.string.apply, (dialog, which) -> {
appPref.setPref(AppPref.PREF_APP_THEME, currentTheme);
appPref.setPref(AppPref.PrefKey.PREF_APP_THEME_INT, currentTheme);
AppCompatDelegate.setDefaultNightMode(currentTheme);
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
......@@ -76,20 +80,20 @@ public class SettingsActivity extends AppCompatActivity {
.create()
.show());
rootSwitcher.setOnCheckedChangeListener((buttonView, isChecked) -> {
appPref.setPref(AppPref.PREF_ROOT_MODE_ENABLED, isChecked);
appPref.setPref(AppPref.PrefKey.PREF_ROOT_MODE_ENABLED_BOOL, isChecked);
blockingView.setVisibility(isChecked ? View.VISIBLE : View.GONE);
});
blockingSwitcher.setOnCheckedChangeListener((buttonView, isChecked) -> {
appPref.setPref(AppPref.PREF_GLOBAL_BLOCKING_ENABLED, isChecked);
appPref.setPref(AppPref.PrefKey.PREF_GLOBAL_BLOCKING_ENABLED_BOOL, isChecked);
if (AppPref.isRootEnabled() && isChecked) {
ComponentsBlocker.applyAllRules(this);
}
});
usageSwitcher.setOnCheckedChangeListener((buttonView, isChecked) ->
appPref.setPref(AppPref.PREF_USAGE_ACCESS_ENABLED, isChecked));
appPref.setPref(AppPref.PrefKey.PREF_USAGE_ACCESS_ENABLED_BOOL, isChecked));
// Import/Export
if ((Boolean) appPref.getPref(AppPref.PREF_ROOT_MODE_ENABLED, AppPref.TYPE_BOOLEAN)) {
if (AppPref.isRootEnabled()) {
findViewById(R.id.import_view).setOnClickListener(v ->
(new ImportExportDialogFragment()).show(getSupportFragmentManager(),
ImportExportDialogFragment.TAG));
......@@ -98,24 +102,21 @@ public class SettingsActivity extends AppCompatActivity {
}
findViewById(R.id.about_view).setOnClickListener(v -> {
View view = getLayoutInflater().inflate(R.layout.dialog_about, null);
try {
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
String version = packageInfo.versionName;
long versionCode;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
versionCode = packageInfo.getLongVersionCode();
} else versionCode = packageInfo.versionCode;
((TextView) view.findViewById(R.id.version)).setText(String.format(Locale.ROOT,
"%s (%d)", version, versionCode));
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
new FullscreenDialog(this)
.setTitle(R.string.about)
.setView(view)
.show();
View view = getLayoutInflater().inflate(R.layout.dialog_about, null);
((TextView) view.findViewById(R.id.version)).setText(String.format(Locale.ROOT,
"%s (%d)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
new FullscreenDialog(this).setTitle(R.string.about).setView(view).show();
});
findViewById(R.id.changelog_view).setOnClickListener(v -> new Thread(() -> {
final Spanned spannedChangelog = HtmlCompat.fromHtml(Utils.getContentFromAssets(this, "changelog.html"), HtmlCompat.FROM_HTML_MODE_COMPACT);
runOnUiThread(() ->
new MaterialAlertDialogBuilder(this, R.style.AppTheme_AlertDialog)
.setTitle(R.string.changelog)
.setMessage(spannedChangelog)
.setNegativeButton(android.R.string.ok, null)
.show());
}).start());
}
@Override
......
......@@ -106,16 +106,7 @@ public class IconPickerDialogFragment extends DialogFragment {
PackageInfo pack = all_packages.get(i);
try {
String icon_resource_name = pm.getResourcesForApplication(pack.packageName).getResourceName(pack.applicationInfo.icon);
if (icon_resource_name != null) {
icons.add(icon_resource_name);
}
// FIXME: Get icons for all activities
// for (int j = 0; j < pack.activities.length; ++j) {
// String icon_resource_name = pm.getResourcesForApplication(pack.packageName).getResourceName(pack.activities[i].getIconResource());
// if (icon_resource_name != null) {
// icons.add(icon_resource_name);
// }
// }
if (icon_resource_name != null) icons.add(icon_resource_name);
} catch (PackageManager.NameNotFoundException | RuntimeException ignored) {}
}
......
......@@ -111,8 +111,6 @@ public class ExternalComponentsImporter {
private static void applyFromWatt(@NonNull Context context, Uri fileUri) throws FileNotFoundException {
String filename = Utils.getName(context.getContentResolver(), fileUri);
if (filename == null) throw new FileNotFoundException("The requested content is not found.");
InputStream inputStream = context.getContentResolver().openInputStream(fileUri);
if (inputStream == null) throw new FileNotFoundException("The requested content is not found.");
try {
try (InputStream rulesStream = context.getContentResolver().openInputStream(fileUri)) {
XmlPullParser parser = Xml.newPullParser();
......
......@@ -66,17 +66,13 @@ public final class IOUtils {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
if (children == null) return false;
for (String child : children) {
for (String child: children) {
boolean success = deleteDir(new File(dir, child));
if (!success) {
return false;
}
if (!success) return false;
}
return dir.delete();
} else if(dir!= null && dir.isFile()) {
} else if(dir != null && dir.isFile()) {
return dir.delete();
} else {
return false;
}
} else return false;
}
}
......@@ -2,17 +2,16 @@ package io.github.muntashirakon.AppManager.utils;
import android.app.Activity;
import android.graphics.Typeface;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.LinearLayoutCompat;
import io.github.muntashirakon.AppManager.R;
import androidx.cardview.widget.CardView;
......@@ -20,7 +19,7 @@ import androidx.cardview.widget.CardView;
@SuppressWarnings({"unused", "UnusedReturnValue"})
public class ListItemCreator {
private Activity mActivity;
private LinearLayout mListContainer;
private LinearLayoutCompat mListContainer;
private LayoutInflater mLayoutInflater;
private static final int EMPTY = -1;
......@@ -156,7 +155,7 @@ public class ListItemCreator {
int padding_small = mActivity.getResources().getDimensionPixelOffset(R.dimen.padding_small);
int padding_very_small = mActivity.getResources().getDimensionPixelOffset(R.dimen.padding_very_small);
int padding_medium = mActivity.getResources().getDimensionPixelOffset(R.dimen.padding_medium);
LinearLayout item_layout = list_item.findViewById(R.id.item_layout);
LinearLayoutCompat item_layout = list_item.findViewById(R.id.item_layout);
item_layout.setPadding(padding_medium, padding_small, padding_medium, padding_very_small);
item_title.setTypeface(Typeface.DEFAULT);
}
......
......@@ -31,10 +31,13 @@ import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
......@@ -58,6 +61,7 @@ import javax.xml.xpath.XPathFactory;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.github.muntashirakon.AppManager.BuildConfig;
import io.github.muntashirakon.AppManager.R;
import io.github.muntashirakon.AppManager.runner.RootShellRunner;
......@@ -192,6 +196,24 @@ public class Utils {
}
}
@NonNull
public static String getContentFromAssets(@NonNull Context context, String fileName) {
try {
InputStream inputStream = context.getResources().getAssets().open(fileName);
byte[] buffer = new byte[1024];
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
for (int length = inputStream.read(buffer); length != -1; length = inputStream.read(buffer)) {
outputStream.write(buffer, 0, length);
}
inputStream.close();
outputStream.close();
return new String(outputStream.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
@NonNull
public static String getFileContent(@NonNull ContentResolver contentResolver, @NonNull Uri file)
throws FileNotFoundException {
......@@ -651,4 +673,14 @@ public class Utils {
}
return false;
}
public static boolean isAppUpdated() {
long newVersionCode = BuildConfig.VERSION_CODE;
long oldVersionCode = (long) AppPref.get(AppPref.PrefKey.PREF_LAST_VERSION_CODE_LONG);
return oldVersionCode != 0 && oldVersionCode < newVersionCode;
}
public static boolean isAppInstalled() { // or data cleared
return (long) AppPref.get(AppPref.PrefKey.PREF_LAST_VERSION_CODE_LONG) == 0;
}
}
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?colorAccent"
android:pathData="M10,8L8,8v4L4,12v2h4v4h2v-4h4v-2h-4L10,8zM14.5,6.08L14.5,7.9l2.5,-0.5L17,18h2L19,5l-4.5,1.08z"/>
</vector>
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.AppInfoActivity">
<include layout="@layout/appbar" />
<io.github.muntashirakon.AppManager.types.ScrollSafeSwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<ScrollView
android:id="@+id/details_scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/details_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="@dimen/padding_medium"
android:paddingEnd="@dimen/padding_medium"
android:paddingTop="@dimen/padding_medium">
<ImageView
android:id="@+id/icon"
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_marginStart="@dimen/padding_medium"
android:layout_marginEnd="@dimen/padding_medium"
android:layout_marginTop="@dimen/padding_medium"
android:layout_marginBottom="@dimen/padding_small"
tools:srcCompat="@tools:sample/avatars"
tools:ignore="contentDescription" />
<TextView
android:id="@+id/label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textIsSelectable="true"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="?android:attr/textColorPrimary"
tools:text="@tools:sample/lorem" />
<TextView
android:id="@+id/packageName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textIsSelectable="true"
android:textStyle="italic"
tools:text="@tools:sample/lorem" />
<TextView
android:id="@+id/version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textIsSelectable="true"
tools:text="@tools:sample/us_zipcodes" />
</LinearLayout>
<com.google.android.material.chip.ChipGroup
android:id="@+id/tag_cloud"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/padding_medium"
android:layout_marginEnd="@dimen/padding_medium"
android:layout_gravity="center" />
<LinearLayout
android:layout_marginTop="@dimen/padding_small"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider" />
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/horizontal_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="8dp"
android:paddingTop="4dp"
android:paddingEnd="8dp"
android:paddingBottom="4dp" />
</HorizontalScrollView>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider" />
</LinearLayout>
<LinearLayout
android:id="@+id/details_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>
</ScrollView>
</io.github.muntashirakon.AppManager.types.ScrollSafeSwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
......@@ -25,7 +25,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/no_tracker_class" />
tools:text="@string/no_tracker_class" />
</FrameLayout>
......
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.SettingsActivity">
<include layout="@layout/appbar" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
......@@ -40,20 +40,6 @@
android:text="@string/main_window_description"
android:textSize="@dimen/subtitle_font" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_medium"
android:text="@string/app_info_window"
android:textSize="@dimen/title_font"
android:textColor="?android:attr/textColorPrimary" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/app_info_window_description"
android:textSize="@dimen/subtitle_font" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
......
......@@ -12,7 +12,7 @@
app:cardCornerRadius="0dp"
app:cardElevation="0dp">
<LinearLayout
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/item_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
......@@ -31,7 +31,7 @@
tools:ignore="ContentDescription"
tools:srcCompat="@tools:sample/avatars" />
<LinearLayout
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/item_text_view_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
......@@ -52,9 +52,9 @@
android:layout_height="wrap_content"
android:textSize="@dimen/subtitle_font"
tools:text="@tools:sample/lorem" />
</LinearLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
<ImageButton
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/item_open"
android:layout_width="56dp"
android:layout_height="56dp"
......@@ -67,6 +67,6 @@
android:src="@drawable/ic_open_in_new_black_24dp"
tools:ignore="ContentDescription,UnusedAttribute" />
</LinearLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.cardview.widget.CardView>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
\ No newline at end of file
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<io.github.muntashirakon.AppManager.types.ScrollSafeSwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:id="@+id/details_scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.progressindicator.ProgressIndicator
android:id="@+id/progress_linear"
style="@style/Widget.MaterialComponents.ProgressIndicator.Linear.Indeterminate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:indicatorColor="?colorAccent" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/details_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="@dimen/padding_medium"
android:paddingEnd="@dimen/padding_medium">
<ImageView
android:id="@+id/icon"
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_marginStart="@dimen/padding_medium"
android:layout_marginEnd="@dimen/padding_medium"
android:layout_marginTop="@dimen/padding_medium"
android:layout_marginBottom="@dimen/padding_small"
tools:srcCompat="@tools:sample/avatars"
tools:ignore="contentDescription" />
<TextView
android:id="@+id/label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textIsSelectable="true"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="?android:attr/textColorPrimary"
tools:text="@tools:sample/lorem" />
<TextView
android:id="@+id/packageName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textIsSelectable="true"
android:textStyle="italic"
tools:text="@tools:sample/lorem" />
<TextView
android:id="@+id/version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textIsSelectable="true"
tools:text="@tools:sample/us_zipcodes" />
</androidx.appcompat.widget.LinearLayoutCompat>
<com.google.android.material.chip.ChipGroup
android:id="@+id/tag_cloud"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/padding_medium"
android:layout_marginEnd="@dimen/padding_medium"
android:layout_gravity="center" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_marginTop="@dimen/padding_small"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider" />
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/horizontal_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="8dp"
android:paddingTop="4dp"
android:paddingEnd="8dp"
android:paddingBottom="4dp" />
</HorizontalScrollView>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/details_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</androidx.appcompat.widget.LinearLayoutCompat>
</ScrollView>
</io.github.muntashirakon.AppManager.types.ScrollSafeSwipeRefreshLayout>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_app_info"
android:icon="@drawable/ic_info_outline_black_24dp"
android:title="@string/app_info"
app:showAsAction="ifRoom" />
</menu>
\ No newline at end of file
......@@ -62,6 +62,11 @@
android:title="@string/refresh"
app:showAsAction="never" />
<item
android:id="@+id/action_one_click_ops"
android:icon="@drawable/ic_outline_plus_one_24"
android:title="@string/one_click_ops" />
<item
android:id="@+id/action_app_usage"
android:icon="@drawable/ic_data_usage_black_24dp"
......
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_show_details"
android:icon="@drawable/ic_view_list_black_24dp"
android:title="@string/show_details"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_refresh_detail"
android:icon="@drawable/ic_refresh_black_24dp"
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="TAB_TITLES">
<item>@string/app_info</item>
<item>@string/activities</item>
<item>@string/service</item>
<item>@string/receivers</item>
......
This diff is collapsed.
VERSION_NAME=2.5.9
VERSION_CODE=312
VERSION_NAME=2.5.10
VERSION_CODE=316
- [Feature] Merged App Info as a single tab in App Details
- [Feature] Added option to reset all app ops
- [Feature] Added option to revoke all dangerous app ops/permissions
- [Feature] Highlight trackers in the component tabs
- [Feature] Added option to save manifest and class dump
- [Feature] Added the ability to grant/revoke development permissions
- [Feature] Added sorting options for components, app ops and uses permissions tabs
- [Feature] Added sort by wifi usage in the App Usage window
- [Feature] Added launch button in the App Info tab
- [Feature] Added never ask option to usage status prompt
- [Feature] Added long click to select apps in the main window
- [Feature] Added changelog within the app
- [Fix] Click to select apps during selection mode
- [Fix] Improved component blocker
- [Fix] Improved manifest loading for large apps
- [Fix] Improved tab loading performance
- [Fix] Fixed app ops checking and custom app ops for some devices
- [Fix] Disabled activity opening for disabled activities
- [Fix] Get real activity name for activities that use activity-alias
- [Fix] Fixed background colors
- [Fix] Fixed crashing when loading the services tab for non-root users
- [Fix] Fixed back button for class viewer which was not working
- [Fix] Changed block icon's colour to accent colour
- [Fix] Removed translation until the app is complete
- [Fix] Made links in the credit section clickable
- [Fix] Fixed various memory leaks