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);
}
}
}