Java tutorial
package biz.bokhorst.xprivacy; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.TreeMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Process; import android.support.v4.view.MenuItemCompat; import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.ViewParent; import android.view.Window; import android.view.WindowManager; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.BaseExpandableListAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.EditText; import android.widget.ExpandableListView; import android.widget.Filter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.RadioGroup; import android.widget.RelativeLayout; import android.widget.ScrollView; import android.widget.SearchView; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; public class ActivityMain extends ActivityBase implements OnItemSelectedListener { private Spinner spRestriction = null; private AppListAdapter mAppAdapter = null; private String searchQuery = ""; private int mSortMode; private boolean mSortInvert; private int mProgressWidth = 0; private int mProgress = 0; private Handler mProHandler = new Handler(); private static final int SORT_BY_NAME = 0; private static final int SORT_BY_UID = 1; private static final int SORT_BY_INSTALL_TIME = 2; private static final int SORT_BY_UPDATE_TIME = 3; private static final int SORT_BY_MODIFY_TIME = 4; private static final int SORT_BY_STATE = 5; private static final int ACTIVITY_LICENSE = 0; private static final int LICENSED = 0x0100; private static final int NOT_LICENSED = 0x0231; private static final int RETRY = 0x0123; private static final int ERROR_CONTACTING_SERVER = 0x101; private static final int ERROR_INVALID_PACKAGE_NAME = 0x102; private static final int ERROR_NON_MATCHING_UID = 0x103; public static final String cAction = "Action"; public static final int cActionRefresh = 1; public static final Uri cProUri = Uri.parse("http://www.xprivacy.eu/"); private static ExecutorService mExecutor = Executors .newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new PriorityThreadFactory()); private static class PriorityThreadFactory implements ThreadFactory { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); t.setPriority(Thread.NORM_PRIORITY); return t; } } private Comparator<ApplicationInfoEx> mSorter = new Comparator<ApplicationInfoEx>() { @Override public int compare(ApplicationInfoEx appInfo0, ApplicationInfoEx appInfo1) { int sortOrder = mSortInvert ? -1 : 1; switch (mSortMode) { case SORT_BY_NAME: return sortOrder * appInfo0.compareTo(appInfo1); case SORT_BY_UID: // Default lowest first return sortOrder * (appInfo0.getUid() - appInfo1.getUid()); case SORT_BY_INSTALL_TIME: // Default newest first Long iTime0 = appInfo0.getInstallTime(ActivityMain.this); Long iTime1 = appInfo1.getInstallTime(ActivityMain.this); return sortOrder * iTime1.compareTo(iTime0); case SORT_BY_UPDATE_TIME: // Default newest first Long uTime0 = appInfo0.getUpdateTime(ActivityMain.this); Long uTime1 = appInfo1.getUpdateTime(ActivityMain.this); return sortOrder * uTime1.compareTo(uTime0); case SORT_BY_MODIFY_TIME: // Default newest first Long mTime0 = appInfo0.getModificationTime(ActivityMain.this); Long mTime1 = appInfo1.getModificationTime(ActivityMain.this); return sortOrder * mTime1.compareTo(mTime0); case SORT_BY_STATE: Integer state0 = appInfo0.getState(ActivityMain.this); Integer state1 = appInfo1.getState(ActivityMain.this); if (state0.compareTo(state1) == 0) return sortOrder * appInfo0.compareTo(appInfo1); else return sortOrder * state0.compareTo(state1); } return 0; } }; private boolean mPackageChangeReceiverRegistered = false; private BroadcastReceiver mPackageChangeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { ActivityMain.this.recreate(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final int userId = Util.getUserId(Process.myUid()); // Check privacy service client if (!PrivacyService.checkClient()) return; // Import license file if (Intent.ACTION_VIEW.equals(getIntent().getAction())) if (Util.importProLicense(new File(getIntent().getData().getPath())) != null) Toast.makeText(this, getString(R.string.menu_pro), Toast.LENGTH_LONG).show(); // Set layout setContentView(R.layout.mainlist); setSupportActionBar((Toolbar) findViewById(R.id.widgetToolbar)); getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); // Set sub title if (Util.hasProLicense(this) != null) getSupportActionBar().setSubtitle(R.string.menu_pro); // Annotate Meta.annotate(this.getResources()); // Get localized restriction name List<String> listRestrictionName = new ArrayList<String>( PrivacyManager.getRestrictions(this).navigableKeySet()); listRestrictionName.add(0, getString(R.string.menu_all)); // Build spinner adapter SpinnerAdapter spAdapter = new SpinnerAdapter(this, android.R.layout.simple_spinner_item); spAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spAdapter.addAll(listRestrictionName); // Handle info ImageView imgInfo = (ImageView) findViewById(R.id.imgInfo); imgInfo.setOnClickListener(new View.OnClickListener() { @SuppressLint("SetJavaScriptEnabled") @Override public void onClick(View view) { int position = spRestriction.getSelectedItemPosition(); if (position != AdapterView.INVALID_POSITION) { String query = (position == 0 ? "restrictions" : (String) PrivacyManager.getRestrictions(ActivityMain.this).values().toArray()[position - 1]); WebView webview = new WebView(ActivityMain.this); webview.getSettings().setUserAgentString("Mozilla/5.0"); // needed for hashtag webview.getSettings().setJavaScriptEnabled(true); webview.loadUrl("https://github.com/M66B/XPrivacy#" + query); AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ActivityMain.this); alertDialogBuilder.setTitle((String) spRestriction.getSelectedItem()); alertDialogBuilder.setIcon(getThemed(R.attr.icon_launcher)); alertDialogBuilder.setView(webview); alertDialogBuilder.setCancelable(true); AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } } }); // Setup category spinner spRestriction = (Spinner) findViewById(R.id.spRestriction); spRestriction.setAdapter(spAdapter); spRestriction.setOnItemSelectedListener(this); int pos = getSelectedCategory(userId); spRestriction.setSelection(pos); // Setup sort mSortMode = Integer.parseInt(PrivacyManager.getSetting(userId, PrivacyManager.cSettingSortMode, "0")); mSortInvert = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingSortInverted, false); // Start task to get app list AppListTask appListTask = new AppListTask(); appListTask.executeOnExecutor(mExecutor, (Object) null); // Check environment Requirements.check(this); // Licensing checkLicense(); // Listen for package add/remove IntentFilter iff = new IntentFilter(); iff.addAction(Intent.ACTION_PACKAGE_ADDED); iff.addAction(Intent.ACTION_PACKAGE_REMOVED); iff.addDataScheme("package"); registerReceiver(mPackageChangeReceiver, iff); mPackageChangeReceiverRegistered = true; boolean showChangelog = true; // First run if (PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFirstRun, true)) { showChangelog = false; optionAbout(); } // Tutorial if (!PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingTutorialMain, false)) { showChangelog = false; ((ScrollView) findViewById(R.id.svTutorialHeader)).setVisibility(View.VISIBLE); ((ScrollView) findViewById(R.id.svTutorialDetails)).setVisibility(View.VISIBLE); } View.OnClickListener listener = new View.OnClickListener() { @Override public void onClick(View view) { ViewParent parent = view.getParent(); while (!parent.getClass().equals(ScrollView.class)) parent = parent.getParent(); ((View) parent).setVisibility(View.GONE); PrivacyManager.setSetting(userId, PrivacyManager.cSettingTutorialMain, Boolean.TRUE.toString()); } }; ((Button) findViewById(R.id.btnTutorialHeader)).setOnClickListener(listener); ((Button) findViewById(R.id.btnTutorialDetails)).setOnClickListener(listener); // Legacy if (!PrivacyManager.cVersion3) { long now = new Date().getTime(); String legacy = PrivacyManager.getSetting(userId, PrivacyManager.cSettingLegacy, null); if (legacy == null || now > Long.parseLong(legacy) + 7 * 24 * 60 * 60 * 1000L) { showChangelog = false; PrivacyManager.setSetting(userId, PrivacyManager.cSettingLegacy, Long.toString(now)); AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); alertDialogBuilder.setTitle(R.string.app_name); alertDialogBuilder.setIcon(getThemed(R.attr.icon_launcher)); alertDialogBuilder.setMessage(R.string.title_update_legacy); alertDialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Util.viewUri(ActivityMain.this, Uri.parse("https://github.com/M66B/XPrivacy/blob/master/CHANGELOG.md#xprivacy3")); } }); alertDialogBuilder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // Do nothing } }); // Show dialog AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } } // Show changelog if (showChangelog) { String sVersion = PrivacyManager.getSetting(userId, PrivacyManager.cSettingChangelog, null); Version changelogVersion = new Version(sVersion == null ? "0.0" : sVersion); Version currentVersion = new Version(Util.getSelfVersionName(this)); if (sVersion == null || changelogVersion.compareTo(currentVersion) < 0) optionChangelog(); } } @Override protected void onResume() { super.onResume(); // Update category selection if (spRestriction != null) { int userId = Util.getUserId(Process.myUid()); int pos = getSelectedCategory(userId); spRestriction.setSelection(pos); } // Update list if (mAppAdapter != null) mAppAdapter.notifyDataSetChanged(); } @Override protected void onNewIntent(Intent intent) { // Handle clear XPrivacy data (needs UI refresh) Bundle extras = intent.getExtras(); if (extras != null && extras.containsKey(cAction) && extras.getInt(cAction) == cActionRefresh) recreate(); else { // Refresh application list if (mAppAdapter != null) mAppAdapter.notifyDataSetChanged(); // Import pro license if (Intent.ACTION_VIEW.equals(intent.getAction())) Util.importProLicense(new File(intent.getData().getPath())); } } @Override protected void onDestroy() { super.onDestroy(); if (mPackageChangeReceiverRegistered) { unregisterReceiver(mPackageChangeReceiver); mPackageChangeReceiverRegistered = false; } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent dataIntent) { super.onActivityResult(requestCode, resultCode, dataIntent); if (requestCode == ACTIVITY_LICENSE) { // License check if (dataIntent != null) { int code = dataIntent.getIntExtra("Code", -1); int reason = dataIntent.getIntExtra("Reason", -1); String sReason; if (reason == LICENSED) sReason = "LICENSED"; else if (reason == NOT_LICENSED) sReason = "NOT_LICENSED"; else if (reason == RETRY) sReason = "RETRY"; else if (reason == ERROR_CONTACTING_SERVER) sReason = "ERROR_CONTACTING_SERVER"; else if (reason == ERROR_INVALID_PACKAGE_NAME) sReason = "ERROR_INVALID_PACKAGE_NAME"; else if (reason == ERROR_NON_MATCHING_UID) sReason = "ERROR_NON_MATCHING_UID"; else sReason = Integer.toString(reason); Util.log(null, Log.WARN, "Licensing: code=" + code + " reason=" + sReason); if (code > 0) { Util.setPro(true); invalidateOptionsMenu(); Toast.makeText(this, getString(R.string.menu_pro), Toast.LENGTH_LONG).show(); } else if (reason == RETRY) { Util.setPro(false); mProHandler.postDelayed(new Runnable() { @Override public void run() { checkLicense(); } }, 30 * 1000); } } } } // Filtering @Override public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { selectRestriction(pos); } @Override public void onNothingSelected(AdapterView<?> parent) { selectRestriction(0); } private void selectRestriction(int pos) { if (mAppAdapter != null) { int userId = Util.getUserId(Process.myUid()); String restrictionName = (pos == 0 ? null : (String) PrivacyManager.getRestrictions(this).values().toArray()[pos - 1]); mAppAdapter.setRestrictionName(restrictionName); PrivacyManager.setSetting(userId, PrivacyManager.cSettingSelectedCategory, restrictionName); applyFilter(); } } private void applyFilter() { if (mAppAdapter != null) { ProgressBar pbFilter = (ProgressBar) findViewById(R.id.pbFilter); TextView tvStats = (TextView) findViewById(R.id.tvStats); TextView tvState = (TextView) findViewById(R.id.tvState); // Get settings int userId = Util.getUserId(Process.myUid()); boolean fUsed = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFUsed, false); boolean fInternet = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFInternet, false); boolean fRestriction = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFRestriction, false); boolean fRestrictionNot = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFRestrictionNot, false); boolean fPermission = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFPermission, true); boolean fOnDemand = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFOnDemand, false); boolean fOnDemandNot = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFOnDemandNot, false); boolean fUser = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFUser, true); boolean fSystem = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFSystem, false); String filter = String.format("%s\n%b\n%b\n%b\n%b\n%b\n%b\n%b\n%b\n%b", searchQuery, fUsed, fInternet, fRestriction, fRestrictionNot, fPermission, fOnDemand, fOnDemandNot, fUser, fSystem); pbFilter.setVisibility(ProgressBar.VISIBLE); tvStats.setVisibility(TextView.GONE); // Adjust progress state width RelativeLayout.LayoutParams tvStateLayout = (RelativeLayout.LayoutParams) tvState.getLayoutParams(); tvStateLayout.addRule(RelativeLayout.LEFT_OF, R.id.pbFilter); mAppAdapter.getFilter().filter(filter); } } private void applySort() { if (mAppAdapter != null) mAppAdapter.sort(); } // Options @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); if (inflater != null && PrivacyService.checkClient()) { // Inflate menu inflater.inflate(R.menu.main, menu); // Searchable SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.menu_search)); if (searchView != null) { searchView.setIconifiedByDefault(false); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextChange(String newText) { searchQuery = newText; applyFilter(); return true; } @Override public boolean onQueryTextSubmit(String query) { searchQuery = query; applyFilter(); return true; } }); searchView.setOnCloseListener(new SearchView.OnCloseListener() { @Override public boolean onClose() { searchQuery = ""; applyFilter(); return true; } }); } return true; } else return false; } @Override public boolean onPrepareOptionsMenu(Menu menu) { int userId = Util.getUserId(Process.myUid()); boolean mounted = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); boolean updates = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingUpdates, false); menu.findItem(R.id.menu_export).setEnabled(mounted); menu.findItem(R.id.menu_import).setEnabled(mounted); menu.findItem(R.id.menu_submit).setEnabled(Util.hasValidFingerPrint(this)); menu.findItem(R.id.menu_pro).setVisible(!Util.isProEnabled() && Util.hasProLicense(this) == null); menu.findItem(R.id.menu_dump).setVisible(Util.isDebuggable(this)); menu.findItem(R.id.menu_update).setVisible(updates); menu.findItem(R.id.menu_update).setEnabled(mounted); // Update filter count // Get settings boolean fUsed = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFUsed, false); boolean fInternet = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFInternet, false); boolean fRestriction = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFRestriction, false); boolean fPermission = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFPermission, true); boolean fOnDemand = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFOnDemand, false); boolean fUser = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFUser, true); boolean fSystem = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFSystem, false); // Count number of active filters int numberOfFilters = 0; if (fUsed) numberOfFilters++; if (fInternet) numberOfFilters++; if (fRestriction) numberOfFilters++; if (fPermission) numberOfFilters++; if (fOnDemand) numberOfFilters++; if (fUser) numberOfFilters++; if (fSystem) numberOfFilters++; if (numberOfFilters > 0) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_filter) .copy(Bitmap.Config.ARGB_8888, true); Paint paint = new Paint(); paint.setStyle(Style.FILL); paint.setColor(Color.GRAY); paint.setTextSize(bitmap.getWidth() / 3); paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); String text = Integer.toString(numberOfFilters); Canvas canvas = new Canvas(bitmap); canvas.drawText(text, bitmap.getWidth() - paint.measureText(text), bitmap.getHeight(), paint); MenuItem fMenu = menu.findItem(R.id.menu_filter); fMenu.setIcon(new BitmapDrawable(getResources(), bitmap)); } return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { try { switch (item.getItemId()) { case R.id.menu_sort: optionSort(); return true; case R.id.menu_filter: optionFilter(); return true; case R.id.menu_usage: optionUsage(); return true; case R.id.menu_template: optionTemplate(); return true; case R.id.menu_select_all: optionSelectAll(); return true; case R.id.menu_toggle: optionToggle(); return true; case R.id.menu_export: optionExport(); return true; case R.id.menu_import: optionImport(); return true; case R.id.menu_submit: optionSubmit(); return true; case R.id.menu_fetch: optionFetch(); return true; case R.id.menu_pro: optionPro(); return true; case R.id.menu_theme: optionSwitchTheme(); return true; case R.id.menu_settings: optionSettings(); return true; case R.id.menu_dump: optionDump(); return true; case R.id.menu_legend: optionLegend(); return true; case R.id.menu_tutorial: optionTutorial(); return true; case R.id.menu_changelog: optionChangelog(); return true; case R.id.menu_update: optionUpdate(); return true; case R.id.menu_report: optionReportIssue(); return true; case R.id.menu_about: optionAbout(); return true; default: return super.onOptionsItemSelected(item); } } catch (Throwable ex) { Util.bug(null, ex); return true; } } @SuppressLint("InflateParams") private void optionSort() { LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.sort, null); final RadioGroup rgSMode = (RadioGroup) view.findViewById(R.id.rgSMode); final CheckBox cbSInvert = (CheckBox) view.findViewById(R.id.cbSInvert); // Initialise controls switch (mSortMode) { case SORT_BY_NAME: rgSMode.check(R.id.rbSName); break; case SORT_BY_UID: rgSMode.check(R.id.rbSUid); break; case SORT_BY_INSTALL_TIME: rgSMode.check(R.id.rbSInstalled); break; case SORT_BY_UPDATE_TIME: rgSMode.check(R.id.rbSUpdated); break; case SORT_BY_MODIFY_TIME: rgSMode.check(R.id.rbSModified); break; case SORT_BY_STATE: rgSMode.check(R.id.rbSState); break; } cbSInvert.setChecked(mSortInvert); // Build dialog AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ActivityMain.this); alertDialogBuilder.setTitle(R.string.menu_sort); alertDialogBuilder.setIcon(getThemed(R.attr.icon_launcher)); alertDialogBuilder.setView(view); alertDialogBuilder.setPositiveButton(ActivityMain.this.getString(android.R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (rgSMode.getCheckedRadioButtonId()) { case R.id.rbSName: mSortMode = SORT_BY_NAME; break; case R.id.rbSUid: mSortMode = SORT_BY_UID; break; case R.id.rbSInstalled: mSortMode = SORT_BY_INSTALL_TIME; break; case R.id.rbSUpdated: mSortMode = SORT_BY_UPDATE_TIME; break; case R.id.rbSModified: mSortMode = SORT_BY_MODIFY_TIME; break; case R.id.rbSState: mSortMode = SORT_BY_STATE; break; } mSortInvert = cbSInvert.isChecked(); int userId = Util.getUserId(Process.myUid()); PrivacyManager.setSetting(userId, PrivacyManager.cSettingSortMode, Integer.toString(mSortMode)); PrivacyManager.setSetting(userId, PrivacyManager.cSettingSortInverted, Boolean.toString(mSortInvert)); applySort(); } }); alertDialogBuilder.setNegativeButton(ActivityMain.this.getString(android.R.string.cancel), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // Do nothing } }); // Show dialog AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } @SuppressLint("InflateParams") private void optionFilter() { LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.filters, null); final CheckBox cbFUsed = (CheckBox) view.findViewById(R.id.cbFUsed); final CheckBox cbFInternet = (CheckBox) view.findViewById(R.id.cbFInternet); final CheckBox cbFPermission = (CheckBox) view.findViewById(R.id.cbFPermission); final CheckBox cbFRestriction = (CheckBox) view.findViewById(R.id.cbFRestriction); final CheckBox cbFRestrictionNot = (CheckBox) view.findViewById(R.id.cbFRestrictionNot); final CheckBox cbFOnDemand = (CheckBox) view.findViewById(R.id.cbFOnDemand); final CheckBox cbFOnDemandNot = (CheckBox) view.findViewById(R.id.cbFOnDemandNot); final CheckBox cbFUser = (CheckBox) view.findViewById(R.id.cbFUser); final CheckBox cbFSystem = (CheckBox) view.findViewById(R.id.cbFSystem); final Button btnDefault = (Button) view.findViewById(R.id.btnDefault); // Get settings final int userId = Util.getUserId(Process.myUid()); boolean fUsed = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFUsed, false); boolean fInternet = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFInternet, false); boolean fPermission = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFPermission, true); boolean fRestriction = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFRestriction, false); boolean fRestrictionNot = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFRestrictionNot, false); boolean fOnDemand = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFOnDemand, false); boolean fOnDemandNot = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFOnDemandNot, false); boolean fUser = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFUser, true); boolean fSystem = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFSystem, false); boolean ondemand = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingOnDemand, true); // Setup checkboxes cbFUsed.setChecked(fUsed); cbFInternet.setChecked(fInternet); cbFPermission.setChecked(fPermission); cbFRestriction.setChecked(fRestriction); cbFRestrictionNot.setChecked(fRestrictionNot); cbFOnDemand.setChecked(fOnDemand && ondemand); cbFOnDemandNot.setChecked(fOnDemandNot && ondemand); cbFUser.setChecked(fUser); cbFSystem.setChecked(fSystem); cbFRestrictionNot.setEnabled(fRestriction); cbFOnDemand.setEnabled(ondemand); cbFOnDemandNot.setEnabled(fOnDemand && ondemand); // Manage user/system filter exclusivity OnCheckedChangeListener checkListener = new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (buttonView == cbFUser) { if (isChecked) cbFSystem.setChecked(false); } else if (buttonView == cbFSystem) { if (isChecked) cbFUser.setChecked(false); } else if (buttonView == cbFRestriction) cbFRestrictionNot.setEnabled(cbFRestriction.isChecked()); else if (buttonView == cbFOnDemand) cbFOnDemandNot.setEnabled(cbFOnDemand.isChecked()); } }; cbFUser.setOnCheckedChangeListener(checkListener); cbFSystem.setOnCheckedChangeListener(checkListener); cbFRestriction.setOnCheckedChangeListener(checkListener); cbFOnDemand.setOnCheckedChangeListener(checkListener); // Clear button btnDefault.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { cbFUsed.setChecked(false); cbFInternet.setChecked(false); cbFPermission.setChecked(true); cbFRestriction.setChecked(false); cbFRestrictionNot.setChecked(false); cbFOnDemand.setChecked(false); cbFOnDemandNot.setChecked(false); cbFUser.setChecked(true); cbFSystem.setChecked(false); } }); // Build dialog AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ActivityMain.this); alertDialogBuilder.setTitle(R.string.menu_filter); alertDialogBuilder.setIcon(getThemed(R.attr.icon_launcher)); alertDialogBuilder.setView(view); alertDialogBuilder.setPositiveButton(ActivityMain.this.getString(android.R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { PrivacyManager.setSetting(userId, PrivacyManager.cSettingFUsed, Boolean.toString(cbFUsed.isChecked())); PrivacyManager.setSetting(userId, PrivacyManager.cSettingFInternet, Boolean.toString(cbFInternet.isChecked())); PrivacyManager.setSetting(userId, PrivacyManager.cSettingFRestriction, Boolean.toString(cbFRestriction.isChecked())); PrivacyManager.setSetting(userId, PrivacyManager.cSettingFRestrictionNot, Boolean.toString(cbFRestrictionNot.isChecked())); PrivacyManager.setSetting(userId, PrivacyManager.cSettingFPermission, Boolean.toString(cbFPermission.isChecked())); PrivacyManager.setSetting(userId, PrivacyManager.cSettingFOnDemand, Boolean.toString(cbFOnDemand.isChecked())); PrivacyManager.setSetting(userId, PrivacyManager.cSettingFOnDemandNot, Boolean.toString(cbFOnDemandNot.isChecked())); PrivacyManager.setSetting(userId, PrivacyManager.cSettingFUser, Boolean.toString(cbFUser.isChecked())); PrivacyManager.setSetting(userId, PrivacyManager.cSettingFSystem, Boolean.toString(cbFSystem.isChecked())); invalidateOptionsMenu(); applyFilter(); } }); alertDialogBuilder.setNegativeButton(ActivityMain.this.getString(android.R.string.cancel), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); // Show dialog AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } private void optionUsage() { Intent intent = new Intent(this, ActivityUsage.class); if (mAppAdapter != null && mAppAdapter.getRestrictionName() != null) intent.putExtra(ActivityUsage.cRestriction, mAppAdapter.getRestrictionName()); startActivity(intent); } @SuppressLint("InflateParams") private void optionTemplate() { final int userId = Util.getUserId(Process.myUid()); // Build view LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.template, null); final Spinner spTemplate = (Spinner) view.findViewById(R.id.spTemplate); Button btnRename = (Button) view.findViewById(R.id.btnRename); ExpandableListView elvTemplate = (ExpandableListView) view.findViewById(R.id.elvTemplate); // Template selector final SpinnerAdapter spAdapter = new SpinnerAdapter(this, android.R.layout.simple_spinner_item); spAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); String defaultName = PrivacyManager.getSetting(userId, Meta.cTypeTemplateName, "0", getString(R.string.title_default)); spAdapter.add(defaultName); for (int i = 1; i <= 4; i++) { String alternateName = PrivacyManager.getSetting(userId, Meta.cTypeTemplateName, Integer.toString(i), getString(R.string.title_alternate) + " " + i); spAdapter.add(alternateName); } spTemplate.setAdapter(spAdapter); // Template definition final TemplateListAdapter templateAdapter = new TemplateListAdapter(this, view, R.layout.templateentry); elvTemplate.setAdapter(templateAdapter); elvTemplate.setGroupIndicator(null); spTemplate.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { templateAdapter.notifyDataSetChanged(); } @Override public void onNothingSelected(AdapterView<?> arg0) { templateAdapter.notifyDataSetChanged(); } }); btnRename.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (Util.hasProLicense(ActivityMain.this) == null) { // Redirect to pro page Util.viewUri(ActivityMain.this, cProUri); return; } final int templateId = spTemplate.getSelectedItemPosition(); if (templateId == AdapterView.INVALID_POSITION) return; AlertDialog.Builder dlgRename = new AlertDialog.Builder(spTemplate.getContext()); dlgRename.setTitle(R.string.title_rename); final String original = (templateId == 0 ? getString(R.string.title_default) : getString(R.string.title_alternate) + " " + templateId); dlgRename.setMessage(original); final EditText input = new EditText(spTemplate.getContext()); dlgRename.setView(input); dlgRename.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { String name = input.getText().toString(); if (TextUtils.isEmpty(name)) { PrivacyManager.setSetting(userId, Meta.cTypeTemplateName, Integer.toString(templateId), null); name = original; } else { PrivacyManager.setSetting(userId, Meta.cTypeTemplateName, Integer.toString(templateId), name); } spAdapter.remove(spAdapter.getItem(templateId)); spAdapter.insert(name, templateId); spAdapter.notifyDataSetChanged(); } }); dlgRename.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { // Do nothing } }); dlgRename.create().show(); } }); // Build dialog AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); alertDialogBuilder.setTitle(R.string.menu_template); alertDialogBuilder.setIcon(getThemed(R.attr.icon_launcher)); alertDialogBuilder.setView(view); alertDialogBuilder.setPositiveButton(getString(R.string.msg_done), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // Do nothing } }); // Show dialog AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } private void optionSelectAll() { // Select all visible apps if (mAppAdapter != null) mAppAdapter.selectAllVisible(); } private void optionToggle() { if (mAppAdapter != null) { Intent intent = new Intent(ActivityShare.ACTION_TOGGLE); intent.putExtra(ActivityShare.cInteractive, true); intent.putExtra(ActivityShare.cUidList, mAppAdapter == null ? new int[0] : mAppAdapter.getSelectedOrVisibleUid(0)); intent.putExtra(ActivityShare.cRestriction, mAppAdapter.getRestrictionName()); startActivity(intent); } } private void optionExport() { Intent intent = new Intent(ActivityShare.ACTION_EXPORT); intent.putExtra(ActivityShare.cInteractive, true); intent.putExtra(ActivityShare.cUidList, mAppAdapter == null ? new int[0] : mAppAdapter.getSelectedOrVisibleUid(AppListAdapter.cSelectAppAll)); startActivity(intent); } private void optionImport() { Intent intent = new Intent(ActivityShare.ACTION_IMPORT); intent.putExtra(ActivityShare.cInteractive, true); intent.putExtra(ActivityShare.cUidList, mAppAdapter == null ? new int[0] : mAppAdapter.getSelectedOrVisibleUid(0)); startActivity(intent); } private void optionSubmit() { if (ActivityShare.registerDevice(this)) { int[] uid = (mAppAdapter == null ? new int[0] : mAppAdapter.getSelectedOrVisibleUid(AppListAdapter.cSelectAppNone)); if (uid.length == 0) { AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); alertDialogBuilder.setTitle(R.string.app_name); alertDialogBuilder.setMessage(R.string.msg_select); alertDialogBuilder.setIcon(getThemed(R.attr.icon_launcher)); alertDialogBuilder.setPositiveButton(getString(android.R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } else if (uid.length <= ActivityShare.cSubmitLimit) { if (mAppAdapter != null) { Intent intent = new Intent(ActivityShare.ACTION_SUBMIT); intent.putExtra(ActivityShare.cInteractive, true); intent.putExtra(ActivityShare.cUidList, uid); startActivity(intent); } } else { AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); alertDialogBuilder.setTitle(R.string.app_name); alertDialogBuilder.setMessage(getString(R.string.msg_limit, ActivityShare.cSubmitLimit + 1)); alertDialogBuilder.setIcon(getThemed(R.attr.icon_launcher)); alertDialogBuilder.setPositiveButton(getString(android.R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } } } private void optionFetch() { if (Util.hasProLicense(this) == null) { // Redirect to pro page Util.viewUri(this, cProUri); } else { if (mAppAdapter != null) { Intent intent = new Intent(ActivityShare.ACTION_FETCH); intent.putExtra(ActivityShare.cInteractive, true); intent.putExtra(ActivityShare.cUidList, mAppAdapter == null ? new int[0] : mAppAdapter.getSelectedOrVisibleUid(0)); startActivity(intent); } } } private void optionPro() { // Redirect to pro page Util.viewUri(this, cProUri); } private void optionSwitchTheme() { int userId = Util.getUserId(Process.myUid()); String themeName = PrivacyManager.getSetting(userId, PrivacyManager.cSettingTheme, ""); themeName = (themeName.equals("Dark") ? "Light" : "Dark"); PrivacyManager.setSetting(userId, PrivacyManager.cSettingTheme, themeName); this.recreate(); } private void optionSettings() { Intent intent = new Intent(this, ActivitySettings.class); startActivity(intent); } private void optionDump() { try { PrivacyService.getClient().dump(0); } catch (Throwable ex) { Util.bug(null, ex); } } private void optionLegend() { // Show help Dialog dialog = new Dialog(ActivityMain.this); dialog.requestWindowFeature(Window.FEATURE_LEFT_ICON); dialog.setTitle(R.string.menu_legend); dialog.setContentView(R.layout.legend); dialog.setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, getThemed(R.attr.icon_launcher)); ((ImageView) dialog.findViewById(R.id.imgHelpHalf)).setImageBitmap(getHalfCheckBox()); ((ImageView) dialog.findViewById(R.id.imgHelpOnDemand)).setImageBitmap(getOnDemandCheckBox()); for (View child : Util.getViewsByTag((ViewGroup) dialog.findViewById(android.R.id.content), "details")) child.setVisibility(View.GONE); ((LinearLayout) dialog.findViewById(R.id.llUnsafe)) .setVisibility(PrivacyManager.cVersion3 ? View.VISIBLE : View.GONE); dialog.setCancelable(true); dialog.show(); } private void optionTutorial() { ((ScrollView) findViewById(R.id.svTutorialHeader)).setVisibility(View.VISIBLE); ((ScrollView) findViewById(R.id.svTutorialDetails)).setVisibility(View.VISIBLE); int userId = Util.getUserId(Process.myUid()); PrivacyManager.setSetting(userId, PrivacyManager.cSettingTutorialMain, Boolean.FALSE.toString()); Dialog dlgUsage = new Dialog(this); dlgUsage.requestWindowFeature(Window.FEATURE_LEFT_ICON); dlgUsage.setTitle(R.string.title_usage_header); dlgUsage.setContentView(R.layout.usage); dlgUsage.setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, getThemed(R.attr.icon_launcher)); dlgUsage.setCancelable(true); dlgUsage.show(); } private void optionChangelog() { WebView webview = new WebView(this); webview.setWebViewClient(new WebViewClient() { public void onPageFinished(WebView view, String url) { int userId = Util.getUserId(Process.myUid()); Version currentVersion = new Version(Util.getSelfVersionName(ActivityMain.this)); PrivacyManager.setSetting(userId, PrivacyManager.cSettingChangelog, currentVersion.toString()); } }); webview.loadUrl("https://github.com/M66B/XPrivacy/blob/master/CHANGELOG.md"); AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); alertDialogBuilder.setTitle(R.string.menu_changelog); alertDialogBuilder.setIcon(getThemed(R.attr.icon_launcher)); alertDialogBuilder.setView(webview); AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } private void optionUpdate() { if (Util.hasProLicense(this) == null) Util.viewUri(this, ActivityMain.cProUri); else new ActivityShare.UpdateTask(this).executeOnExecutor(mExecutor); } private void optionReportIssue() { // Report issue Util.viewUri(this, Uri.parse("https://github.com/M66B/XPrivacy#support")); } @SuppressLint("DefaultLocale") private void optionAbout() { // About Dialog dlgAbout = new Dialog(this); dlgAbout.requestWindowFeature(Window.FEATURE_LEFT_ICON); dlgAbout.setTitle(R.string.menu_about); dlgAbout.setContentView(R.layout.about); dlgAbout.setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, getThemed(R.attr.icon_launcher)); // Show version try { int userId = Util.getUserId(Process.myUid()); Version currentVersion = new Version(Util.getSelfVersionName(this)); Version storedVersion = new Version( PrivacyManager.getSetting(userId, PrivacyManager.cSettingVersion, "0.0")); boolean migrated = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingMigrated, false); String versionName = currentVersion.toString(); if (currentVersion.compareTo(storedVersion) != 0) versionName += "/" + storedVersion.toString(); if (!migrated) versionName += "!"; int versionCode = Util.getSelfVersionCode(this); TextView tvVersion = (TextView) dlgAbout.findViewById(R.id.tvVersion); tvVersion.setText(String.format(getString(R.string.app_version), versionName, versionCode)); } catch (Throwable ex) { Util.bug(null, ex); } if (!PrivacyManager.cVersion3 || Hook.isAOSP(19)) ((TextView) dlgAbout.findViewById(R.id.tvCompatibility)).setVisibility(View.GONE); // Show license String licensed = Util.hasProLicense(this); TextView tvLicensed1 = (TextView) dlgAbout.findViewById(R.id.tvLicensed); TextView tvLicensed2 = (TextView) dlgAbout.findViewById(R.id.tvLicensedAlt); if (licensed == null) { tvLicensed1.setText(Environment.getExternalStorageDirectory().getAbsolutePath()); tvLicensed2.setText(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) .getAbsolutePath()); } else { tvLicensed1.setText(String.format(getString(R.string.app_licensed), licensed)); tvLicensed2.setVisibility(View.GONE); } // Show some build properties String android = String.format("%s (%d)", Build.VERSION.RELEASE, Build.VERSION.SDK_INT); ((TextView) dlgAbout.findViewById(R.id.tvAndroid)).setText(android); ((TextView) dlgAbout.findViewById(R.id.build_brand)).setText(Build.BRAND); ((TextView) dlgAbout.findViewById(R.id.build_manufacturer)).setText(Build.MANUFACTURER); ((TextView) dlgAbout.findViewById(R.id.build_model)).setText(Build.MODEL); ((TextView) dlgAbout.findViewById(R.id.build_product)).setText(Build.PRODUCT); ((TextView) dlgAbout.findViewById(R.id.build_device)).setText(Build.DEVICE); ((TextView) dlgAbout.findViewById(R.id.build_host)).setText(Build.HOST); ((TextView) dlgAbout.findViewById(R.id.build_display)).setText(Build.DISPLAY); ((TextView) dlgAbout.findViewById(R.id.build_id)).setText(Build.ID); dlgAbout.setCancelable(true); final int userId = Util.getUserId(Process.myUid()); if (PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingFirstRun, true)) dlgAbout.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { Dialog dlgUsage = new Dialog(ActivityMain.this); dlgUsage.requestWindowFeature(Window.FEATURE_LEFT_ICON); dlgUsage.setTitle(R.string.app_name); dlgUsage.setContentView(R.layout.usage); dlgUsage.setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, getThemed(R.attr.icon_launcher)); dlgUsage.setCancelable(true); dlgUsage.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { PrivacyManager.setSetting(userId, PrivacyManager.cSettingFirstRun, Boolean.FALSE.toString()); optionLegend(); } }); dlgUsage.show(); } }); dlgAbout.show(); } // Tasks private class AppListTask extends AsyncTask<Object, Integer, List<ApplicationInfoEx>> { private String mRestrictionName; private ProgressDialog mProgressDialog; @Override protected List<ApplicationInfoEx> doInBackground(Object... params) { mRestrictionName = null; // Delegate return ApplicationInfoEx.getXApplicationList(ActivityMain.this, mProgressDialog); } @SuppressWarnings("deprecation") @Override protected void onPreExecute() { super.onPreExecute(); TypedArray ta = getTheme().obtainStyledAttributes(new int[] { R.attr.progress_horizontal }); int progress_horizontal = ta.getResourceId(0, 0); ta.recycle(); // Show progress dialog mProgressDialog = new ProgressDialog(ActivityMain.this); mProgressDialog.setMessage(getString(R.string.msg_loading)); mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mProgressDialog.setProgressDrawable(getResources().getDrawable(progress_horizontal)); mProgressDialog.setProgressNumberFormat(null); mProgressDialog.setCancelable(false); mProgressDialog.setCanceledOnTouchOutside(false); mProgressDialog.show(); } @Override protected void onPostExecute(List<ApplicationInfoEx> listApp) { if (!ActivityMain.this.isFinishing()) { // Display app list mAppAdapter = new AppListAdapter(ActivityMain.this, R.layout.mainentry, listApp, mRestrictionName); ListView lvApp = (ListView) findViewById(R.id.lvApp); lvApp.setAdapter(mAppAdapter); // Dismiss progress dialog if (mProgressDialog.isShowing()) try { mProgressDialog.dismiss(); } catch (IllegalArgumentException ignored) { } // Restore state ActivityMain.this.selectRestriction(spRestriction.getSelectedItemPosition()); } super.onPostExecute(listApp); } } // Adapters private class SpinnerAdapter extends ArrayAdapter<String> { public SpinnerAdapter(Context context, int textViewResourceId) { super(context, textViewResourceId); } } @SuppressLint("DefaultLocale") private class TemplateListAdapter extends BaseExpandableListAdapter { private View mView; private Spinner mSpinner; private List<String> listRestrictionName; private List<String> listLocalizedTitle; private boolean ondemand; private Version version; private LayoutInflater mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); public TemplateListAdapter(Context context, View view, int resource) { mView = view; mSpinner = (Spinner) view.findViewById(R.id.spTemplate); // Get restriction categories TreeMap<String, String> tmRestriction = PrivacyManager.getRestrictions(context); listRestrictionName = new ArrayList<String>(tmRestriction.values()); listLocalizedTitle = new ArrayList<String>(tmRestriction.navigableKeySet()); int userId = Util.getUserId(Process.myUid()); ondemand = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingOnDemand, true); version = new Version(Util.getSelfVersionName(context)); } private String getTemplate() { if (mSpinner.getSelectedItemPosition() == 0) return Meta.cTypeTemplate; else return Meta.cTypeTemplate + mSpinner.getSelectedItemPosition(); } private class ViewHolder { private View row; public ImageView imgIndicator; public ImageView imgInfo; public TextView tvRestriction; public ImageView imgUnsafe; public ImageView imgCbRestrict; public ImageView imgCbAsk; public boolean restricted; public boolean asked; public ViewHolder(View theRow) { row = theRow; imgIndicator = (ImageView) row.findViewById(R.id.imgIndicator); imgInfo = (ImageView) row.findViewById(R.id.imgInfo); tvRestriction = (TextView) row.findViewById(R.id.tvRestriction); imgUnsafe = (ImageView) row.findViewById(R.id.imgUnsafe); imgCbRestrict = (ImageView) row.findViewById(R.id.imgCbRestrict); imgCbAsk = (ImageView) row.findViewById(R.id.imgCbAsk); } } @Override public Object getGroup(int groupPosition) { return listRestrictionName.get(groupPosition); } @Override public int getGroupCount() { return listRestrictionName.size(); } @Override public long getGroupId(int groupPosition) { return groupPosition; } @Override @SuppressLint("InflateParams") public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { final ViewHolder holder; if (convertView == null) { convertView = mInflater.inflate(R.layout.templateentry, null); holder = new ViewHolder(convertView); convertView.setTag(holder); } else holder = (ViewHolder) convertView.getTag(); // Get entry final String restrictionName = (String) getGroup(groupPosition); // Get info final int userId = Util.getUserId(Process.myUid()); String value = PrivacyManager.getSetting(userId, getTemplate(), restrictionName, Boolean.toString(!ondemand) + "+ask"); holder.restricted = value.contains("true"); holder.asked = (!ondemand || value.contains("asked")); boolean partialRestricted = false; boolean partialAsked = false; if (holder.restricted || !holder.asked) for (Hook hook : PrivacyManager.getHooks(restrictionName, version)) { String settingName = restrictionName + "." + hook.getName(); String childValue = PrivacyManager.getSetting(userId, getTemplate(), settingName, null); if (childValue == null) childValue = Boolean.toString(holder.restricted && !hook.isDangerous()) + (holder.asked || (hook.isDangerous() && hook.whitelist() == null) ? "+asked" : "+ask"); if (!childValue.contains("true")) partialRestricted = true; if (childValue.contains("asked")) partialAsked = true; } Bitmap bmRestricted = (holder.restricted ? partialRestricted ? getHalfCheckBox() : getFullCheckBox() : getOffCheckBox()); Bitmap bmAsked = (holder.asked ? getOffCheckBox() : partialAsked ? getHalfCheckBox() : getOnDemandCheckBox()); // Indicator state holder.imgIndicator.setImageResource( getThemed(isExpanded ? R.attr.icon_expander_maximized : R.attr.icon_expander_minimized)); holder.imgIndicator.setVisibility(View.VISIBLE); holder.imgInfo.setVisibility(View.GONE); holder.imgUnsafe.setVisibility(View.GONE); // Set data holder.tvRestriction.setTypeface(null, Typeface.BOLD); holder.tvRestriction.setText(listLocalizedTitle.get(groupPosition)); holder.imgCbRestrict.setImageBitmap(bmRestricted); holder.imgCbAsk.setImageBitmap(bmAsked); holder.imgCbAsk.setVisibility(ondemand ? View.VISIBLE : View.GONE); holder.imgCbRestrict.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // Update setting holder.restricted = !holder.restricted; PrivacyManager.setSetting(userId, getTemplate(), restrictionName, (holder.restricted ? "true" : "false") + "+" + (holder.asked ? "asked" : "ask")); notifyDataSetChanged(); // update childs } }); holder.imgCbAsk.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // Update setting holder.asked = (!ondemand || !holder.asked); PrivacyManager.setSetting(userId, getTemplate(), restrictionName, (holder.restricted ? "true" : "false") + "+" + (holder.asked ? "asked" : "ask")); notifyDataSetChanged(); // update childs } }); return convertView; } @Override public Object getChild(int groupPosition, int childPosition) { return PrivacyManager.getHooks((String) getGroup(groupPosition), version).get(childPosition); } @Override public long getChildId(int groupPosition, int childPosition) { return childPosition; } @Override public int getChildrenCount(int groupPosition) { return PrivacyManager.getHooks((String) getGroup(groupPosition), version).size(); } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return false; } @Override @SuppressLint("InflateParams") public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { final ViewHolder holder; if (convertView == null) { convertView = mInflater.inflate(R.layout.templateentry, null); holder = new ViewHolder(convertView); convertView.setTag(holder); } else holder = (ViewHolder) convertView.getTag(); // Get entry final int userId = Util.getUserId(Process.myUid()); final String restrictionName = (String) getGroup(groupPosition); final Hook hook = (Hook) getChild(groupPosition, childPosition); final String settingName = restrictionName + "." + hook.getName(); // Get parent info String parentValue = PrivacyManager.getSetting(userId, getTemplate(), restrictionName, Boolean.toString(!ondemand) + "+ask"); boolean parentRestricted = parentValue.contains("true"); boolean parentAsked = (!ondemand || parentValue.contains("asked")); // Get child info String value = PrivacyManager.getSetting(userId, getTemplate(), settingName, null); // This is to circumvent caching problems // The child value depends on the parent value if (value == null) value = Boolean.toString(parentRestricted && !hook.isDangerous()) + (parentAsked || (hook.isDangerous() && hook.whitelist() == null) ? "+asked" : "+ask"); holder.restricted = value.contains("true"); holder.asked = (!ondemand || value.contains("asked")); Bitmap bmRestricted = (parentRestricted && holder.restricted ? getFullCheckBox() : getOffCheckBox()); Bitmap bmAsked = (parentAsked || holder.asked ? getOffCheckBox() : getOnDemandCheckBox()); // Set indicator holder.imgIndicator.setVisibility(View.INVISIBLE); // Function help if (hook.getAnnotation() == null) holder.imgInfo.setVisibility(View.GONE); else { holder.imgInfo.setVisibility(View.VISIBLE); holder.imgInfo.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ActivityApp.showHelp(ActivityMain.this, mView, hook); } }); } holder.imgUnsafe.setVisibility(hook.isUnsafe() ? View.VISIBLE : View.GONE); // Set data if (hook.isDangerous()) holder.row.setBackgroundColor(getResources().getColor(getThemed( hook.isDangerousDefined() ? R.attr.color_dangerous : R.attr.color_dangerous_user))); else holder.row.setBackgroundColor( hook.isDangerousDefined() ? getResources().getColor(getThemed(R.attr.color_dangerous_off)) : Color.TRANSPARENT); holder.tvRestriction.setText(hook.getName()); holder.imgCbRestrict.setEnabled(parentRestricted); holder.imgCbRestrict.setImageBitmap(bmRestricted); holder.imgCbAsk.setEnabled(!parentAsked); holder.imgCbAsk.setImageBitmap(bmAsked); holder.imgCbAsk.setVisibility(ondemand ? View.VISIBLE : View.GONE); // Listen for long press if (Util.getUserId(Process.myUid()) == 0) holder.tvRestriction.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { hook.toggleDangerous(); // Change background color if (hook.isDangerous()) holder.row.setBackgroundColor(getResources() .getColor(getThemed(hook.isDangerousDefined() ? R.attr.color_dangerous : R.attr.color_dangerous_user))); else holder.row.setBackgroundColor(hook.isDangerousDefined() ? getResources().getColor(getThemed(R.attr.color_dangerous_off)) : Color.TRANSPARENT); notifyDataSetChanged(); return true; } }); holder.imgCbRestrict.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { // Update setting holder.restricted = !holder.restricted; PrivacyManager.setSetting(userId, getTemplate(), settingName, (holder.restricted ? "true" : "false") + "+" + (holder.asked ? "asked" : "ask")); notifyDataSetChanged(); // update parent } }); holder.imgCbAsk.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { // Update setting holder.asked = !holder.asked; PrivacyManager.setSetting(userId, getTemplate(), settingName, (holder.restricted ? "true" : "false") + "+" + (holder.asked ? "asked" : "ask")); notifyDataSetChanged(); // update parent } }); return convertView; } @Override public boolean hasStableIds() { return true; } } @SuppressLint("DefaultLocale") private class AppListAdapter extends ArrayAdapter<ApplicationInfoEx> { private Context mContext; private boolean mSelecting = false; private List<ApplicationInfoEx> mListAppAll; private List<ApplicationInfoEx> mListAppSelected = new ArrayList<ApplicationInfoEx>(); private String mRestrictionName; private Version mVersion; private LayoutInflater mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); private AtomicInteger mFiltersRunning = new AtomicInteger(0); private int mHighlightColor; public final static int cSelectAppAll = 1; public final static int cSelectAppNone = 2; public AppListAdapter(Context context, int resource, List<ApplicationInfoEx> objects, String initialRestrictionName) { super(context, resource, objects); mContext = context; mListAppAll = new ArrayList<ApplicationInfoEx>(); mListAppAll.addAll(objects); mRestrictionName = initialRestrictionName; mVersion = new Version(Util.getSelfVersionName(context)); TypedArray ta1 = context.getTheme() .obtainStyledAttributes(new int[] { android.R.attr.colorPressedHighlight }); mHighlightColor = ta1.getColor(0, 0xFF00FF); ta1.recycle(); } public void setRestrictionName(String restrictionName) { mRestrictionName = restrictionName; } public String getRestrictionName() { return mRestrictionName; } public List<ApplicationInfoEx> getSelectedOrVisible(int flags) { if (mListAppSelected.size() > 0) return mListAppSelected; else { if (flags == cSelectAppAll) return mListAppAll; else { List<ApplicationInfoEx> listApp = new ArrayList<ApplicationInfoEx>(); if (flags != cSelectAppNone) for (int i = 0; i < this.getCount(); i++) listApp.add(this.getItem(i)); return listApp; } } } public int[] getSelectedOrVisibleUid(int flags) { List<ApplicationInfoEx> listAppInfo = getSelectedOrVisible(flags); int[] uid = new int[listAppInfo.size()]; for (int pos = 0; pos < listAppInfo.size(); pos++) uid[pos] = listAppInfo.get(pos).getUid(); return uid; } public void selectAllVisible() { // Look through the visible apps to figure out what to do mSelecting = false; for (int i = 0; i < this.getCount(); i++) { if (!mListAppSelected.contains(this.getItem(i))) { mSelecting = true; break; } } if (mSelecting) { // Add the visible apps not already selected for (int i = 0; i < this.getCount(); i++) if (!mListAppSelected.contains(this.getItem(i))) mListAppSelected.add(this.getItem(i)); } else mListAppSelected.clear(); this.showStats(); this.notifyDataSetChanged(); } public void showStats() { TextView tvStats = (TextView) findViewById(R.id.tvStats); String stats = String.format("%d/%d", this.getCount(), mListAppAll.size()); if (mListAppSelected.size() > 0) stats += String.format(" (%d)", mListAppSelected.size()); tvStats.setText(stats); } @Override public Filter getFilter() { return new AppFilter(); } private class AppFilter extends Filter { public AppFilter() { } @Override protected FilterResults performFiltering(CharSequence constraint) { int userId = Util.getUserId(Process.myUid()); int filtersRunning = mFiltersRunning.addAndGet(1); FilterResults results = new FilterResults(); // Get arguments String[] components = ((String) constraint).split("\\n"); String fName = components[0]; boolean fUsed = Boolean.parseBoolean(components[1]); boolean fInternet = Boolean.parseBoolean(components[2]); boolean fRestricted = Boolean.parseBoolean(components[3]); boolean fRestrictedNot = Boolean.parseBoolean(components[4]); boolean fPermission = Boolean.parseBoolean(components[5]); boolean fOnDemand = Boolean.parseBoolean(components[6]); boolean fOnDemandNot = Boolean.parseBoolean(components[7]); boolean fUser = Boolean.parseBoolean(components[8]); boolean fSystem = Boolean.parseBoolean(components[9]); // Match applications int current = 0; int max = AppListAdapter.this.mListAppAll.size(); List<ApplicationInfoEx> lstApp = new ArrayList<ApplicationInfoEx>(); for (ApplicationInfoEx xAppInfo : AppListAdapter.this.mListAppAll) { // Check if another filter has been started if (filtersRunning != mFiltersRunning.get()) return null; // Send progress info to main activity current++; if (current % 5 == 0) { final int position = current; final int maximum = max; runOnUiThread(new Runnable() { @Override public void run() { setProgress(getString(R.string.msg_applying), position, maximum); } }); } // Get if name contains boolean contains = false; if (!fName.equals("")) contains = (xAppInfo.toString().toLowerCase().contains(((String) fName).toLowerCase())); // Get if used boolean used = false; if (fUsed) used = (PrivacyManager.getUsage(xAppInfo.getUid(), mRestrictionName, null) != 0); // Get if internet boolean internet = false; if (fInternet) internet = xAppInfo.hasInternet(mContext); // Get some restricted boolean someRestricted = false; if (fRestricted) for (PRestriction restriction : PrivacyManager.getRestrictionList(xAppInfo.getUid(), mRestrictionName)) if (restriction.restricted) { someRestricted = true; break; } // Get Android permission boolean permission = false; if (fPermission) if (mRestrictionName == null) permission = true; else if (PrivacyManager.hasPermission(mContext, xAppInfo, mRestrictionName, mVersion) || PrivacyManager.getUsage(xAppInfo.getUid(), mRestrictionName, null) > 0) permission = true; // Get if onDemand boolean onDemand = false; boolean isApp = PrivacyManager.isApplication(xAppInfo.getUid()); boolean odSystem = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingOnDemandSystem, false); boolean gondemand = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingOnDemand, true); if (fOnDemand && (isApp || odSystem) && gondemand) { onDemand = PrivacyManager.getSettingBool(-xAppInfo.getUid(), PrivacyManager.cSettingOnDemand, false); if (onDemand && mRestrictionName != null) onDemand = !PrivacyManager.getRestrictionEx(xAppInfo.getUid(), mRestrictionName, null).asked; } // Get if user boolean user = false; if (fUser) user = !xAppInfo.isSystem(); // Get if system boolean system = false; if (fSystem) system = xAppInfo.isSystem(); // Apply filters if ((fName.equals("") ? true : contains) && (fUsed ? used : true) && (fInternet ? internet : true) && (fRestricted ? (fRestrictedNot ? !someRestricted : someRestricted) : true) && (fPermission ? permission : true) && (fOnDemand ? (fOnDemandNot ? !onDemand : onDemand) : true) && (fUser ? user : true) && (fSystem ? system : true)) lstApp.add(xAppInfo); } // Check again whether another filter has been started if (filtersRunning != mFiltersRunning.get()) return null; // Apply current sorting Collections.sort(lstApp, mSorter); // Last check whether another filter has been started if (filtersRunning != mFiltersRunning.get()) return null; synchronized (this) { results.values = lstApp; results.count = lstApp.size(); } return results; } @Override @SuppressWarnings("unchecked") protected void publishResults(CharSequence constraint, FilterResults results) { if (results != null) { clear(); TextView tvStats = (TextView) findViewById(R.id.tvStats); TextView tvState = (TextView) findViewById(R.id.tvState); ProgressBar pbFilter = (ProgressBar) findViewById(R.id.pbFilter); pbFilter.setVisibility(ProgressBar.GONE); tvStats.setVisibility(TextView.VISIBLE); runOnUiThread(new Runnable() { @Override public void run() { setProgress(getString(R.string.title_restrict), 0, 1); } }); // Adjust progress state width RelativeLayout.LayoutParams tvStateLayout = (RelativeLayout.LayoutParams) tvState .getLayoutParams(); tvStateLayout.addRule(RelativeLayout.LEFT_OF, R.id.tvStats); if (results.values == null) notifyDataSetInvalidated(); else { addAll((ArrayList<ApplicationInfoEx>) results.values); notifyDataSetChanged(); } AppListAdapter.this.showStats(); } } } public void sort() { sort(mSorter); } private class ViewHolder { private View row; private int position; public View vwState; public LinearLayout llAppType; public ImageView imgIcon; public ImageView imgUsed; public ImageView imgGranted; public ImageView imgInternet; public ImageView imgFrozen; public ImageView imgSettings; public LinearLayout llName; public TextView tvName; public ImageView imgCbRestricted; public ProgressBar pbRunning; public ImageView imgCbAsk; public ViewHolder(View theRow, int thePosition) { row = theRow; position = thePosition; vwState = (View) row.findViewById(R.id.vwState); llAppType = (LinearLayout) row.findViewById(R.id.llAppType); imgIcon = (ImageView) row.findViewById(R.id.imgIcon); imgUsed = (ImageView) row.findViewById(R.id.imgUsed); imgGranted = (ImageView) row.findViewById(R.id.imgGranted); imgInternet = (ImageView) row.findViewById(R.id.imgInternet); imgFrozen = (ImageView) row.findViewById(R.id.imgFrozen); imgSettings = (ImageView) row.findViewById(R.id.imgSettings); llName = (LinearLayout) row.findViewById(R.id.llName); tvName = (TextView) row.findViewById(R.id.tvName); imgCbRestricted = (ImageView) row.findViewById(R.id.imgCbRestricted); pbRunning = (ProgressBar) row.findViewById(R.id.pbRunning); imgCbAsk = (ImageView) row.findViewById(R.id.imgCbAsk); } } private class HolderTask extends AsyncTask<Object, Object, Object> { private int position; private ViewHolder holder; private ApplicationInfoEx xAppInfo = null; private int state; private Bitmap bicon; private Drawable dicon; private boolean used; private boolean enabled; private boolean granted; private boolean settings; private RState rstate; private boolean gondemand; private boolean ondemand; private boolean can; private boolean methodExpert; public HolderTask(int thePosition, ViewHolder theHolder, ApplicationInfoEx theAppInfo) { position = thePosition; holder = theHolder; xAppInfo = theAppInfo; } @Override protected Object doInBackground(Object... params) { if (xAppInfo != null) { int userId = Util.getUserId(Process.myUid()); // Get state state = xAppInfo.getState(ActivityMain.this); // Get icon bicon = xAppInfo.getIconBitmap(ActivityMain.this); if (bicon == null) dicon = xAppInfo.getIcon(ActivityMain.this); // Get if used used = (PrivacyManager.getUsage(xAppInfo.getUid(), mRestrictionName, null) != 0); // Get if enabled enabled = PrivacyManager.getSettingBool(xAppInfo.getUid(), PrivacyManager.cSettingRestricted, true); // Get if on demand gondemand = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingOnDemand, true); boolean isApp = PrivacyManager.isApplication(xAppInfo.getUid()); boolean odSystem = PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingOnDemandSystem, false); ondemand = (isApp || odSystem); if (ondemand && mRestrictionName != null) ondemand = PrivacyManager.getSettingBool(-xAppInfo.getUid(), PrivacyManager.cSettingOnDemand, false); // Get if granted granted = true; if (mRestrictionName != null) if (!PrivacyManager.hasPermission(ActivityMain.this, xAppInfo, mRestrictionName, mVersion)) granted = false; // Get if application settings settings = PrivacyManager.hasSpecificSettings(xAppInfo.getUid()); // Get restriction/ask state rstate = new RState(xAppInfo.getUid(), mRestrictionName, null, mVersion); // Get can restrict can = PrivacyManager.canRestrict(rstate.mUid, Process.myUid(), rstate.mRestrictionName, rstate.mMethodName, true); methodExpert = (mRestrictionName == null || PrivacyManager.getSettingBool(userId, PrivacyManager.cSettingMethodExpert, false)); return holder; } return null; } @Override protected void onPostExecute(Object result) { if (holder.position == position && result != null) { // Set background color if (xAppInfo.isSystem()) holder.llAppType .setBackgroundColor(getResources().getColor(getThemed(R.attr.color_dangerous))); else holder.llAppType.setBackgroundColor(Color.TRANSPARENT); // Display state if (state == ApplicationInfoEx.STATE_ATTENTION) holder.vwState.setBackgroundColor( getResources().getColor(getThemed(R.attr.color_state_attention))); else if (state == ApplicationInfoEx.STATE_SHARED) holder.vwState .setBackgroundColor(getResources().getColor(getThemed(R.attr.color_state_shared))); else holder.vwState.setBackgroundColor( getResources().getColor(getThemed(R.attr.color_state_restricted))); // Display icon if (bicon == null) holder.imgIcon.setImageDrawable(dicon); else holder.imgIcon.setImageBitmap(bicon); holder.imgIcon.setVisibility(View.VISIBLE); // Display on demand if (gondemand) { if (ondemand) { holder.imgCbAsk.setImageBitmap(getAskBoxImage(rstate, methodExpert)); holder.imgCbAsk.setVisibility(View.VISIBLE); } else holder.imgCbAsk.setVisibility(View.INVISIBLE); } else holder.imgCbAsk.setVisibility(View.GONE); // Display usage holder.tvName.setTypeface(null, used ? Typeface.BOLD_ITALIC : Typeface.NORMAL); holder.imgUsed.setVisibility(used ? View.VISIBLE : View.INVISIBLE); // Display if permissions holder.imgGranted.setVisibility(granted ? View.VISIBLE : View.INVISIBLE); // Display if internet access holder.imgInternet .setVisibility(xAppInfo.hasInternet(ActivityMain.this) ? View.VISIBLE : View.INVISIBLE); // Display if frozen holder.imgFrozen .setVisibility(xAppInfo.isFrozen(ActivityMain.this) ? View.VISIBLE : View.INVISIBLE); // Display if settings holder.imgSettings.setVisibility(settings ? View.VISIBLE : View.GONE); // Display restriction holder.imgCbRestricted.setImageBitmap(getCheckBoxImage(rstate, methodExpert)); holder.imgCbRestricted.setVisibility(View.VISIBLE); // Display enabled state holder.tvName.setEnabled(enabled && can); holder.imgCbRestricted.setEnabled(enabled && can); holder.imgCbAsk.setEnabled(enabled && can); // Display selection if (mListAppSelected.contains(xAppInfo)) holder.row.setBackgroundColor(mHighlightColor); else holder.row.setBackgroundColor(Color.TRANSPARENT); // Handle details click holder.imgIcon.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intentSettings = new Intent(ActivityMain.this, ActivityApp.class); intentSettings.putExtra(ActivityApp.cUid, xAppInfo.getUid()); intentSettings.putExtra(ActivityApp.cRestrictionName, mRestrictionName); ActivityMain.this.startActivity(intentSettings); } }); // Listen for restriction changes holder.imgCbRestricted.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mRestrictionName == null && rstate.restricted != false) { AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ActivityMain.this); alertDialogBuilder.setTitle(R.string.menu_clear_all); alertDialogBuilder.setMessage(R.string.msg_sure); alertDialogBuilder.setIcon(getThemed(R.attr.icon_launcher)); alertDialogBuilder.setPositiveButton(getString(android.R.string.ok), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { deleteRestrictions(); } }); alertDialogBuilder.setNegativeButton(getString(android.R.string.cancel), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } else toggleRestrictions(); } }); // Listen for ask changes if (gondemand && ondemand) holder.imgCbAsk.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { holder.imgCbAsk.setVisibility(View.GONE); holder.pbRunning.setVisibility(View.VISIBLE); new AsyncTask<Object, Object, Object>() { @Override protected Object doInBackground(Object... arg0) { rstate.toggleAsked(); rstate = new RState(xAppInfo.getUid(), mRestrictionName, null, mVersion); return null; } @Override protected void onPostExecute(Object result) { holder.imgCbAsk.setImageBitmap(getAskBoxImage(rstate, methodExpert)); holder.pbRunning.setVisibility(View.GONE); holder.imgCbAsk.setVisibility(View.VISIBLE); } }.executeOnExecutor(mExecutor); } }); else holder.imgCbAsk.setClickable(false); } } private void deleteRestrictions() { holder.imgCbRestricted.setVisibility(View.GONE); holder.pbRunning.setVisibility(View.VISIBLE); new AsyncTask<Object, Object, Object>() { private List<Boolean> oldState; @Override protected Object doInBackground(Object... arg0) { // Update restriction oldState = PrivacyManager.getRestartStates(xAppInfo.getUid(), mRestrictionName); PrivacyManager.deleteRestrictions(xAppInfo.getUid(), null, true); PrivacyManager.setSetting(xAppInfo.getUid(), PrivacyManager.cSettingOnDemand, Boolean.toString(true)); return null; } @Override protected void onPostExecute(Object result) { // Update visible state holder.vwState.setBackgroundColor( getResources().getColor(getThemed(R.attr.color_state_attention))); // Update stored state rstate = new RState(xAppInfo.getUid(), mRestrictionName, null, mVersion); holder.imgCbRestricted.setImageBitmap(getCheckBoxImage(rstate, methodExpert)); holder.imgCbAsk.setImageBitmap(getAskBoxImage(rstate, methodExpert)); // Notify restart if (oldState.contains(true)) Toast.makeText(ActivityMain.this, getString(R.string.msg_restart), Toast.LENGTH_LONG) .show(); // Display new state showState(); holder.pbRunning.setVisibility(View.GONE); holder.imgCbRestricted.setVisibility(View.VISIBLE); } }.executeOnExecutor(mExecutor); } private void toggleRestrictions() { holder.imgCbRestricted.setVisibility(View.GONE); holder.pbRunning.setVisibility(View.VISIBLE); new AsyncTask<Object, Object, Object>() { private List<Boolean> oldState; private List<Boolean> newState; @Override protected Object doInBackground(Object... arg0) { // Change restriction oldState = PrivacyManager.getRestartStates(xAppInfo.getUid(), mRestrictionName); rstate.toggleRestriction(); newState = PrivacyManager.getRestartStates(xAppInfo.getUid(), mRestrictionName); return null; } @Override protected void onPostExecute(Object result) { // Update restriction display rstate = new RState(xAppInfo.getUid(), mRestrictionName, null, mVersion); holder.imgCbRestricted.setImageBitmap(getCheckBoxImage(rstate, methodExpert)); holder.imgCbAsk.setImageBitmap(getAskBoxImage(rstate, methodExpert)); // Notify restart if (!newState.equals(oldState)) Toast.makeText(ActivityMain.this, getString(R.string.msg_restart), Toast.LENGTH_LONG) .show(); // Display new state showState(); holder.pbRunning.setVisibility(View.GONE); holder.imgCbRestricted.setVisibility(View.VISIBLE); } }.executeOnExecutor(mExecutor); } private void showState() { state = xAppInfo.getState(ActivityMain.this); if (state == ApplicationInfoEx.STATE_ATTENTION) holder.vwState .setBackgroundColor(getResources().getColor(getThemed(R.attr.color_state_attention))); else if (state == ApplicationInfoEx.STATE_SHARED) holder.vwState .setBackgroundColor(getResources().getColor(getThemed(R.attr.color_state_shared))); else holder.vwState .setBackgroundColor(getResources().getColor(getThemed(R.attr.color_state_restricted))); } } @Override @SuppressLint("InflateParams") public View getView(int position, View convertView, ViewGroup parent) { final ViewHolder holder; if (convertView == null) { convertView = mInflater.inflate(R.layout.mainentry, null); holder = new ViewHolder(convertView, position); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); holder.position = position; } // Get info final ApplicationInfoEx xAppInfo = getItem(holder.position); // Set data holder.row.setBackgroundColor(Color.TRANSPARENT); holder.vwState.setBackgroundColor(Color.TRANSPARENT); holder.llAppType.setBackgroundColor(Color.TRANSPARENT); holder.imgIcon.setVisibility(View.INVISIBLE); holder.tvName.setText(xAppInfo.toString()); holder.tvName.setTypeface(null, Typeface.NORMAL); holder.imgUsed.setVisibility(View.INVISIBLE); holder.imgGranted.setVisibility(View.INVISIBLE); holder.imgInternet.setVisibility(View.INVISIBLE); holder.imgFrozen.setVisibility(View.INVISIBLE); holder.imgSettings.setVisibility(View.GONE); holder.imgCbRestricted.setVisibility(View.INVISIBLE); holder.imgCbAsk.setVisibility(View.INVISIBLE); holder.tvName.setEnabled(false); holder.imgCbRestricted.setEnabled(false); holder.imgIcon.setClickable(false); holder.imgCbRestricted.setClickable(false); holder.imgCbAsk.setClickable(false); // Listen for multiple select holder.llName.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { if (mListAppSelected.contains(xAppInfo)) { mSelecting = false; mListAppSelected.clear(); mAppAdapter.notifyDataSetChanged(); } else { mSelecting = true; mListAppSelected.add(xAppInfo); holder.row.setBackgroundColor(mHighlightColor); } showStats(); return true; } }); // Listen for application selection holder.llName.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View view) { if (mSelecting) { if (mListAppSelected.contains(xAppInfo)) { mListAppSelected.remove(xAppInfo); holder.row.setBackgroundColor(Color.TRANSPARENT); if (mListAppSelected.size() == 0) mSelecting = false; } else { mListAppSelected.add(xAppInfo); holder.row.setBackgroundColor(mHighlightColor); } showStats(); } else { Intent intentSettings = new Intent(ActivityMain.this, ActivityApp.class); intentSettings.putExtra(ActivityApp.cUid, xAppInfo.getUid()); intentSettings.putExtra(ActivityApp.cRestrictionName, mRestrictionName); ActivityMain.this.startActivity(intentSettings); } } }); // Async update new HolderTask(position, holder, xAppInfo).executeOnExecutor(mExecutor, (Object) null); return convertView; } } // Helper methods private void setProgress(String text, int progress, int max) { // Set up the progress bar if (mProgressWidth == 0) { final View vProgressEmpty = (View) findViewById(R.id.vProgressEmpty); mProgressWidth = vProgressEmpty.getMeasuredWidth(); } // Display stuff TextView tvState = (TextView) findViewById(R.id.tvState); if (text != null) tvState.setText(text); if (max == 0) max = 1; mProgress = (int) ((float) mProgressWidth) * progress / max; View vProgressFull = (View) findViewById(R.id.vProgressFull); vProgressFull.getLayoutParams().width = mProgress; } private int getSelectedCategory(final int userId) { int pos = 0; String restrictionName = PrivacyManager.getSetting(userId, PrivacyManager.cSettingSelectedCategory, null); if (restrictionName != null) for (String restriction : PrivacyManager.getRestrictions(this).values()) { pos++; if (restrictionName.equals(restriction)) break; } return pos; } private void checkLicense() { if (!Util.isProEnabled() && Util.hasProLicense(this) == null) if (Util.isProEnablerInstalled(this)) try { int uid = getPackageManager().getPackageInfo("biz.bokhorst.xprivacy.pro", 0).applicationInfo.uid; PrivacyManager.deleteRestrictions(uid, null, true); Util.log(null, Log.INFO, "Licensing: check"); startActivityForResult(new Intent("biz.bokhorst.xprivacy.pro.CHECK"), ACTIVITY_LICENSE); } catch (Throwable ex) { Util.bug(null, ex); } } }