More root stuff

Because we can can can...
This commit is contained in:
d8ahazard 2016-09-19 16:48:13 -05:00
parent 3fe5647a15
commit 8a8aa1337b
12 changed files with 211 additions and 251 deletions

View File

@ -12,12 +12,24 @@
tools:ignore="ProtectedPermissions" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
<service
android:label="@string/accessibility_service_name"
android:name=".MonitorService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibilityservice"/>
</service>
<activity
android:name=".WelcomeActivity"
android:exported="true"
@ -73,9 +85,6 @@
</intent-filter>
</receiver>
<service
android:name=".MonitorService"
android:exported="false" />
</application>
</manifest>

View File

@ -9,7 +9,6 @@ import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -30,7 +29,7 @@ public class AutoRootFragment extends ListFragment {
private ApplicationAdapter listadaptor = null;
public ListView listView;
public SharedPreferences prefs;
List<String> arrayBlackList, arrayWhiteList;
List<String> arrayBlackList;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@ -49,9 +48,6 @@ public class AutoRootFragment extends ListFragment {
set.add("com.google.android.apps.walletnfcrel");
set.add("com.google.android.gms");
editor.putStringSet("auto_blacklist", set);
set.clear();
set.add("com.kermidas.TitaniumBackupPro");
editor.putStringSet("auto_whitelist", set);
editor.apply();
}
new LoadApplications().execute();
@ -75,29 +71,15 @@ public class AutoRootFragment extends ListFragment {
private void ToggleApp(String appToCheck, int position, View v) {
Set<String> blackListSet = prefs.getStringSet("auto_blacklist", null);
Set<String> whiteListSet = prefs.getStringSet("auto_whitelist", null);
assert blackListSet != null;
arrayBlackList = new ArrayList<>(blackListSet);
assert whiteListSet != null;
arrayWhiteList = new ArrayList<>(whiteListSet);
Log.d("Magisk", "Trying to toggle for " + appToCheck + " stringset is " + arrayBlackList.toString());
if ((!arrayBlackList.contains(appToCheck)) && (!arrayWhiteList.contains(appToCheck))) {
Log.d("Magisk", "App is not in any array, adding to whitelist");
arrayWhiteList.add(appToCheck);
} else if (arrayWhiteList.contains(appToCheck)) {
Log.d("Magisk", "App is in whitelist, moving to blacklist");
for (int i = 0; i < arrayWhiteList.size(); i++) {
if (appToCheck.equals(arrayWhiteList.get(i))) {
arrayWhiteList.remove(i);
}
}
if (!arrayBlackList.contains(appToCheck)) {
arrayBlackList.add(appToCheck);
} else if (arrayBlackList.contains(appToCheck)) {
Log.d("Magisk", "App is in Blacklist, removing");
} else {
for (int i = 0; i < arrayBlackList.size(); i++) {
if (appToCheck.equals(arrayBlackList.get(i))) {
arrayBlackList.remove(i);
@ -105,12 +87,7 @@ public class AutoRootFragment extends ListFragment {
}
}
Set<String> set2 = new HashSet<>(arrayBlackList);
Log.d("Magisk", "Committing set, value is: " + set2);
SharedPreferences.Editor editor = prefs.edit();
editor.putStringSet("auto_blacklist", new HashSet<>(arrayBlackList));
editor.putStringSet("auto_whitelist", new HashSet<>(arrayWhiteList));
editor.apply();
prefs.edit().putStringSet("auto_blacklist", new HashSet<>(arrayBlackList)).apply();
listadaptor.UpdateRootStatusView(position, v);
}

View File

@ -1,36 +1,28 @@
package com.topjohnwu.magisk;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.ComponentName;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
public class MonitorService extends Service
{
public class MonitorService extends AccessibilityService {
private static final String TAG = "Magisk";
private final Handler handler = new Handler();
private Boolean disableroot;
@ -38,65 +30,85 @@ public class MonitorService extends Service
private int counter = 0;
private String mPackageName = "";
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
protected void onServiceConnected() {
super.onServiceConnected();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
//Configure these here for compatibility with API 13 and below.
AccessibilityServiceInfo config = new AccessibilityServiceInfo();
config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
disableroot = false;
disablerootprev = disableroot;
if (Build.VERSION.SDK_INT >= 16)
//Just in case this helps
config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
setServiceInfo(config);
}
@Override
public void onCreate() {
super.onCreate();
checkProcesses.run();
Log.d("Magisk","MonitorService: Service created");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("Magisk","MonitorService: Service destroyed");
public void onAccessibilityEvent(AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
ComponentName componentName = new ComponentName(
event.getPackageName().toString(),
event.getClassName().toString()
);
ActivityInfo activityInfo = tryGetActivity(componentName);
boolean isActivity = activityInfo != null;
if (isActivity) {
Log.i("Magisk","CurrentActivity: " + componentName.getPackageName());
String mPackage = componentName.getPackageName();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (prefs.getBoolean("autoRootEnable", false)) {
Set<String> setBlackList = prefs.getStringSet("auto_blacklist", null);
Set<String> setWhiteList = prefs.getStringSet("auto_whitelist", null);
if (setBlackList != null) {
disableroot = setBlackList.contains(mPackage);
if (disableroot) {
ForceDisableRoot();
} else {
ForceEnableRoot();
}
String appFriendly = getAppName(mPackage);
ShowNotification(disableroot,appFriendly);
}
}
}
}
}
private Runnable checkProcesses = new Runnable() {
@Override
public void run() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (prefs.getBoolean("autoRootEnable", false)) {
Set<String> setBlackList = prefs.getStringSet("auto_blacklist", null);
Set<String> setWhiteList = prefs.getStringSet("auto_whitelist", null);
if (setBlackList != null) {
disableroot = getStats(setBlackList);
}
if (disableroot != disablerootprev) {
String rootstatus = (disableroot ? "disabled" : "enabled");
if (disableroot) {
ForceDisableRoot();
} else {
ForceEnableRoot();
}
ShowNotification(disableroot);
}
disablerootprev = disableroot;
//Log.d(TAG,"Root check completed, set to " + (disableroot ? "disabled" : "enabled"));
}
handler.postDelayed(checkProcesses, 500);
private String getAppName (String packageName) {
PackageManager pkManager = getPackageManager();
ApplicationInfo appInfo;
String appname = "";
try {
appInfo = pkManager.getApplicationInfo(packageName, 0);
appname = (String) ((appInfo != null) ? pkManager.getApplicationLabel(appInfo) : "???");
return appname;
} catch (final PackageManager.NameNotFoundException e) {
return "";
}
}
};
private ActivityInfo tryGetActivity(ComponentName componentName) {
try {
return getPackageManager().getActivityInfo(componentName, 0);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
private void ForceDisableRoot() {
Log.d("Magisk", "MonitorService: Forcedisable called.");
@ -113,10 +125,10 @@ public class MonitorService extends Service
Utils.toggleRoot(true);
if (!Utils.rootEnabled()) {
Utils.toggleRoot(true);
}
}
}
private void ShowNotification(boolean rootAction) {
private void ShowNotification(boolean rootAction, String packageName) {
NotificationManager mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder;
@ -130,10 +142,10 @@ public class MonitorService extends Service
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
if (mPackageName.equals("")) {
if (packageName.equals("")) {
rootMessage = "Root has been disabled";
} else {
rootMessage = "Root has been disabled for " + mPackageName;
rootMessage = "Root has been disabled for " + packageName;
}
mBuilder =
new NotificationCompat.Builder(getApplicationContext())
@ -149,64 +161,7 @@ public class MonitorService extends Service
}
private boolean getStats(Set<String> seti) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
boolean inStats = false;
if (seti != null) {
ArrayList<String> statList = new ArrayList<>(seti);
for (int i = 0; i < statList.size(); i++) {
if (isAppForeground(statList.get(i))) {
inStats = (isAppForeground(statList.get(i)));
}
}
return inStats;
}
Log.d(TAG, "SDK check failed.");
}
return false;
@Override
public void onInterrupt() {
}
private String getAppName (String packageName) {
PackageManager pkManager = getPackageManager();
ApplicationInfo appInfo;
String appname = "";
try {
appInfo = pkManager.getApplicationInfo(packageName, 0);
appname = (String) ((appInfo != null) ? pkManager.getApplicationLabel(appInfo) : "???");
return appname;
} catch (final PackageManager.NameNotFoundException e) {
return null;
}
}
protected boolean isAppForeground(String packageName) {
UsageStatsManager usageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
List<UsageStats> stats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 10, time);
String topPackageName = "";
if (stats != null) {
SortedMap<Long, UsageStats> mySortedMap = new TreeMap<>();
for (UsageStats usageStats : stats) {
mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
}
if (!mySortedMap.isEmpty()) {
topPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
if (topPackageName.equals("com.topjohnwu.magisk")) {
mySortedMap.remove(mySortedMap.lastKey());
topPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
Log.d("Magisk","MonitorService: Package is " + topPackageName);
mPackageName = getAppName(topPackageName);
}
}
}
return topPackageName.equals(packageName);
}
}
}

View File

@ -9,7 +9,6 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
@ -126,13 +125,7 @@ public class RootFragment extends Fragment {
}
private void CheckAccessPermissions() {
if (!Utils.hasStatsPermission(getActivity())) {
Toast.makeText(getActivity(),"Please allow Usage Access for auto root to work.",Toast.LENGTH_LONG).show();
startActivityForResult(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS), 100);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
@ -141,24 +134,27 @@ public class RootFragment extends Fragment {
// Make sure the request was successful
if (resultCode == Activity.RESULT_OK) {
Log.d("Magisk","Got result code OK for permissions");
Toast.makeText(getActivity(),"Auto-root disabled, permissions required.",Toast.LENGTH_LONG).show();
} else {
autoRootToggle.setEnabled(false);
Toast.makeText(getActivity(),"Auto-root disabled, permissions required.",Toast.LENGTH_LONG).show();
}
}
}
private void ToggleAutoRoot(boolean toggleState) {
CheckAccessPermissions();
if (Utils.hasStatsPermission(getActivity())) {
autoRootStatus = toggleState;
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("autoRootEnable", (toggleState));
editor.apply();
if (toggleState) {
if (!Utils.hasStatsPermission(getActivity(),"com.topjohnwu.magisk/WindowChangeDetectingService")) {
Intent intent = new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivityForResult(intent, 100);
}
Intent myIntent = new Intent(getActivity(), MonitorService.class);
getActivity().startService(myIntent);
rootToggle.setEnabled(false);
@ -172,7 +168,7 @@ public class RootFragment extends Fragment {
getActivity().stopService(myIntent);
rootToggle.setEnabled(true);
}
}
}
@Override

View File

@ -9,7 +9,6 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
@ -86,7 +85,7 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
super.onDrawerSlide(drawerView, 0); // this disables the arrow @ completed state
super.onDrawerSlide(drawerView, 0); // this disables the arrow @ completed tate
}
@Override

View File

@ -9,6 +9,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
@ -24,8 +25,6 @@ public class ApplicationAdapter extends ArrayAdapter<ApplicationInfo> {
private PackageManager packageManager;
public ArrayList arrayList;
public SharedPreferences prefs;
private int BLACKLIST_LIST = 1;
private int WHITELIST_LIST = 2;
public ApplicationAdapter(Context context, int textViewResourceId,
List<ApplicationInfo> appsList) {
@ -66,14 +65,14 @@ public class ApplicationAdapter extends ArrayAdapter<ApplicationInfo> {
TextView appName = (TextView) view.findViewById(R.id.app_name);
TextView packageName = (TextView) view.findViewById(R.id.app_paackage);
ImageView iconview = (ImageView) view.findViewById(R.id.app_icon);
ImageView statusview = (ImageView) view.findViewById(R.id.app_status);
CheckBox statusview = (CheckBox) view.findViewById(R.id.checkbox);
appName.setText(applicationInfo.loadLabel(packageManager));
packageName.setText(applicationInfo.packageName);
iconview.setImageDrawable(applicationInfo.loadIcon(packageManager));
if (CheckApp(applicationInfo.packageName, BLACKLIST_LIST)) {
statusview.setImageDrawable(this.context.getDrawable(R.drawable.root));
if (CheckApp(applicationInfo.packageName)) {
statusview.setChecked(true);
} else {
statusview.setImageDrawable(null);
statusview.setChecked(false);
}
}
return view;
@ -88,21 +87,18 @@ public class ApplicationAdapter extends ArrayAdapter<ApplicationInfo> {
}
ApplicationInfo applicationInfo = appsList.get(position);
if (null != applicationInfo) {
ImageView statusview = (ImageView) view.findViewById(R.id.app_status);
if (CheckApp(applicationInfo.packageName, BLACKLIST_LIST)) {
statusview.setImageDrawable(this.context.getDrawable(R.drawable.root));
} else if (CheckApp(applicationInfo.packageName, WHITELIST_LIST)) {
statusview.setImageDrawable(this.context.getDrawable(R.drawable.ic_stat_notification_autoroot_off));
CheckBox statusview = (CheckBox) view.findViewById(R.id.checkbox);
if (CheckApp(applicationInfo.packageName)) {
statusview.setChecked(true);
} else {
statusview.setImageDrawable(null);
statusview.setChecked(false);
}
}
}
private boolean CheckApp(String appToCheck, int list) {
private boolean CheckApp(String appToCheck) {
boolean starter = false;
if (list == BLACKLIST_LIST) {
Set<String> set = prefs.getStringSet("auto_blacklist", null);
if (set != null) {
arrayList = new ArrayList<>(set);
@ -113,18 +109,6 @@ public class ApplicationAdapter extends ArrayAdapter<ApplicationInfo> {
}
}
} else {
Set<String> set = prefs.getStringSet("auto_whitelist", null);
if (set != null) {
arrayList = new ArrayList<>(set);
for (String string : set) {
if (string.equals(appToCheck)) {
starter = true;
}
}
}
}
return starter;
}

View File

@ -1,6 +1,7 @@
package com.topjohnwu.magisk.utils;
import android.Manifest;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AppOpsManager;
@ -23,6 +24,8 @@ import android.support.v7.app.AlertDialog;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
import com.topjohnwu.magisk.ModulesFragment;
@ -171,14 +174,24 @@ public class Utils {
return value;
}
public static boolean hasStatsPermission(Context context) {
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
int mode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
android.os.Process.myUid(), context.getPackageName());
return mode == AppOpsManager.MODE_ALLOWED;
public static boolean hasStatsPermission(Context context, String id) {
AccessibilityManager am = (AccessibilityManager) context
.getSystemService(Context.ACCESSIBILITY_SERVICE);
List<AccessibilityServiceInfo> runningServices = am
.getEnabledAccessibilityServiceList(AccessibilityEvent.TYPES_ALL_MASK);
for (AccessibilityServiceInfo service : runningServices) {
if (id.equals(service.getId())) {
return true;
}
}
return false;
}
public abstract static class DownloadReceiver extends BroadcastReceiver {
public Context mContext;

View File

@ -1,59 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<ImageView
android:id="@+id/app_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:padding="3dp"
android:scaleType="centerCrop"/>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="3dip"
android:layout_marginLeft="8dip"
android:layout_marginRight="8dip"
android:layout_marginTop="3dip"
android:background="?android:attr/selectableItemBackground"
card_view:cardCornerRadius="2dp"
card_view:cardElevation="2dp"
style="@style/Base.CardView">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="10dp">
<LinearLayout
android:id="@+id/lynn"
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/app_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/app_name"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingLeft="5dp"
android:paddingRight="50dp">
<TextView
android:id="@+id/app_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:textStyle="bold"/>
<TextView
android:id="@+id/app_paackage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"></RelativeLayout>
</LinearLayout>
<ImageView
android:id="@+id/app_status"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_gravity="center_horizontal"
android:padding="3dp"
android:scaleType="centerCrop"/>
android:layout_toEndOf="@+id/app_icon"
android:gravity="center_vertical"
android:paddingEnd="3dp"
android:paddingStart="3dp"
android:textStyle="bold" />
<TextView
android:id="@+id/app_paackage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_below="@+id/app_name"
android:layout_toEndOf="@+id/app_icon"
android:gravity="center_vertical"
android:paddingEnd="3dp"
android:paddingStart="3dp" />
<CheckBox
android:id="@+id/checkbox"
android:layout_width="68dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:focusable="false"
android:gravity="center"
android:src="@drawable/ic_menu_overflow_material"
/>
</RelativeLayout>
</LinearLayout>
</android.support.v7.widget.CardView>

View File

@ -6,7 +6,10 @@
<ListView android:id="@android:id/list"
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
android:divider="@android:color/transparent"
android:dividerHeight="10.0sp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="15dp" />
</LinearLayout>

View File

@ -5,10 +5,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="3dip"
android:layout_marginLeft="8dip"
android:layout_marginRight="8dip"
android:layout_marginTop="3dip"
android:layout_margin="8dp"
android:background="?android:attr/selectableItemBackground"
android:minHeight="?android:attr/listPreferredItemHeight"
card_view:cardCornerRadius="2dp"

View File

@ -82,6 +82,8 @@
<string name="permissionNotGranted">This feature will not work without permission to write external storage.</string>
<string name="no_root_access">No root access, functionality limited</string>
<string name="no_thanks">No thanks</string>
<string name="accessibility_service_description">Accessibility service required for Magisk auto-unroot feature</string>
<string name="accessibility_service_name">Magisk Manager</string>
<string name="update_title">%1$s Update!</string>
<string name="update_msg">New version v%2$s of %1$s is available!\nChangelog:\n%3$s</string>
<string name="download_install">Download and install</string>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- These options MUST be specified here in order for the events to be received on first
start in Android 4.1.1 -->
<accessibility-service
xmlns:tools="http://schemas.android.com/tools"
android:accessibilityEventTypes="typeWindowStateChanged"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagIncludeNotImportantViews"
android:description="@string/accessibility_service_description"
xmlns:android="http://schemas.android.com/apk/res/android"
tools:ignore="UnusedAttribute"/>