diff options
author | Trumeet <liangyuteng12345@gmail.com> | 2018-11-25 20:08:43 -0800 |
---|---|---|
committer | Trumeet <liangyuteng12345@gmail.com> | 2018-11-25 20:08:43 -0800 |
commit | c5f5c348be705d88ed731e335eb102fccc7f5880 (patch) | |
tree | ccc1cd4586685018f8bbeda9080dea1bd48a9735 /app/src/main/java | |
download | SysUIController-c5f5c348be705d88ed731e335eb102fccc7f5880.tar SysUIController-c5f5c348be705d88ed731e335eb102fccc7f5880.tar.gz SysUIController-c5f5c348be705d88ed731e335eb102fccc7f5880.tar.bz2 SysUIController-c5f5c348be705d88ed731e335eb102fccc7f5880.zip |
First Commitv1.0α
Diffstat (limited to 'app/src/main/java')
8 files changed, 806 insertions, 0 deletions
diff --git a/app/src/main/java/moe/yuuta/sysuicontroller/Main.java b/app/src/main/java/moe/yuuta/sysuicontroller/Main.java new file mode 100644 index 0000000..100ff9a --- /dev/null +++ b/app/src/main/java/moe/yuuta/sysuicontroller/Main.java @@ -0,0 +1,59 @@ +package moe.yuuta.sysuicontroller; + +import android.app.Activity; +import android.app.Application; +import android.os.Bundle; + +import com.google.firebase.FirebaseApp; +import com.google.firebase.analytics.FirebaseAnalytics; + +import androidx.work.Configuration; +import androidx.work.WorkManager; + +public class Main extends Application { + public static final String GLOBAL_TAG = "SysUIController"; + + @Override + public void onCreate() { + super.onCreate(); + registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { + @Override + public void onActivityCreated(Activity activity, Bundle savedInstanceState) { + unregisterActivityLifecycleCallbacks(this); + FirebaseApp.initializeApp(activity); + FirebaseAnalytics.getInstance(activity); + WorkManager.initialize(activity, new Configuration.Builder().build()); + } + + @Override + public void onActivityStarted(Activity activity) { + + } + + @Override + public void onActivityResumed(Activity activity) { + + } + + @Override + public void onActivityPaused(Activity activity) { + + } + + @Override + public void onActivityStopped(Activity activity) { + + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + + } + + @Override + public void onActivityDestroyed(Activity activity) { + + } + }); + } +} diff --git a/app/src/main/java/moe/yuuta/sysuicontroller/MainActivity.java b/app/src/main/java/moe/yuuta/sysuicontroller/MainActivity.java new file mode 100644 index 0000000..6e783b2 --- /dev/null +++ b/app/src/main/java/moe/yuuta/sysuicontroller/MainActivity.java @@ -0,0 +1,20 @@ +package moe.yuuta.sysuicontroller; + +import android.os.Bundle; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.navigation.Navigation; + +public class MainActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + } + + @Override + public boolean onSupportNavigateUp() { + return Navigation.findNavController(this, R.id.nav_host).navigateUp(); + } +} diff --git a/app/src/main/java/moe/yuuta/sysuicontroller/MainFragment.java b/app/src/main/java/moe/yuuta/sysuicontroller/MainFragment.java new file mode 100644 index 0000000..fd6aecb --- /dev/null +++ b/app/src/main/java/moe/yuuta/sysuicontroller/MainFragment.java @@ -0,0 +1,358 @@ +package moe.yuuta.sysuicontroller; + +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; +import android.util.Log; +import android.util.SparseArray; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.widget.Toast; + +import com.google.android.gms.oss.licenses.OssLicensesMenuActivity; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import eu.chainfire.librootjava.RootIPCReceiver; +import eu.chainfire.librootjavadaemon.RootDaemon; +import eu.chainfire.libsuperuser.Shell; +import moe.shizuku.preference.Preference; +import moe.shizuku.preference.PreferenceCategory; +import moe.shizuku.preference.PreferenceFragment; +import moe.shizuku.preference.PreferenceGroup; +import moe.shizuku.preference.SwitchPreference; +import moe.yuuta.sysuicontroller.about.VersionDialogFragment; +import moe.yuuta.sysuicontroller.core.ControllerService; +import moe.yuuta.sysuicontroller.core.DisableItem; + +import static moe.yuuta.sysuicontroller.Main.GLOBAL_TAG; + +public class MainFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, Shell.OnCommandResultListener { + private static final String TAG = GLOBAL_TAG + ".MainFragment"; + + private static final String ARG_SERVICE = MainFragment.class.getName() + ".ARG_SERVICE"; + private static final int CODE_START = 1; + + private Shell.Interactive mShell; + private volatile IStatusController mService; + + private Preference mStatusPreference; + private SparseArray<SwitchPreference> mDisableMap; + private SparseArray<SwitchPreference> mDisable2Map; + private List<PreferenceGroup> mGroupsShouldBeDisabledBeforeServer = new ArrayList<>(3); + + private RootIPCReceiver<IStatusController> mReceiver = new RootIPCReceiver<IStatusController>(null, ControllerService.CODE_SERVICE) { + @Override + public void onConnect(IStatusController ipc) { + Log.d(TAG, "Connected to remote service"); + mService = ipc; + postStatusUpdate(); + } + + @Override + public void onDisconnect(IStatusController ipc) { + Log.d(TAG, "Disconnected to remote service"); + mService = ipc; + postStatusUpdate(); + } + }; + + private void serializeDisableFlags () { + if (obtainService() == null) return; + SharedPreferences.Editor editor = requireContext().getSharedPreferences("flags", Context.MODE_PRIVATE) + .edit(); + try { + int disableFlags = mService.getDisableFlags(); + editor.putInt("disable_flags", disableFlags); + } catch (RemoteException e) { + Log.e(TAG, "Receive disable flags", e); + } + try { + int disable2Flags = mService.getDisable2Flags(); + editor.putInt("disable2_flags", disable2Flags); + } catch (RemoteException e) { + Log.e(TAG, "Receive disable2 flags", e); + } + editor.apply(); + } + + private void setNotAvailableBatch (@NonNull Set<String> showedKeys, @NonNull PreferenceGroup root) { + for (int i = 0; i < root.getPreferenceCount(); i ++) { + Preference preference = root.getPreference(i); + if (BuildConfig.DEBUG) Log.d(TAG, "Pref " + preference.getKey() + "(" + preference.getClass().getSimpleName() + ")"); + if (preference instanceof PreferenceGroup) { + setNotAvailableBatch(showedKeys, (PreferenceGroup) preference); + continue; + } + if (!(preference instanceof SwitchPreference)) continue; + if (showedKeys.contains(preference.getKey())) continue; + Log.w(TAG, "Key not available for this device: " + preference.getKey()); + setNotAvailable(preference); + } + } + + private void postStatusUpdate () { + new Handler(Looper.getMainLooper()).post(() -> { + Log.d(TAG, "Start update status"); + obtainService(); + boolean enable = mService != null; + for (PreferenceGroup group : mGroupsShouldBeDisabledBeforeServer) { + group.setEnabled(enable); + } + for (int i = 0; i < mDisableMap.size(); i ++) getPreferenceScreen().removePreference(mDisableMap.valueAt(i)); + for (int i = 0; i < mDisable2Map.size(); i ++) getPreferenceScreen().removePreference(mDisable2Map.valueAt(i)); + mDisable2Map.clear(); + mDisableMap.clear(); + if (enable) { + try { + List<DisableItem> available = mService.getAvailableDisableItems(); + Log.d(TAG, "Available disable items: " + available.toString()); + Set<String /* Name (key) */> showedKeys = new HashSet<>(available.size()); + for (DisableItem item : available) { + showedKeys.add(item.getKey().toLowerCase()); + SwitchPreference preference = (SwitchPreference) findPreference(item.getKey().toLowerCase()); + if (preference == null) { + // Create a new one for special keys + preference = new SwitchPreference(requireContext(), null, moe.shizuku.preference.R.attr.switchPreferenceStyle, + R.style.Preference_SwitchPreference); + preference.setKey(item.getKey().toLowerCase()); + preference.setTitle(item.getKey()); + preference.setSummary(R.string.additional_key); + ((PreferenceCategory) findPreference("key_other")).addPreference(preference); + } + preference.setOnPreferenceChangeListener((p, newValue) -> runDisable(item.getFlag(), (Boolean) newValue, item.getKey(), item.isDisable2())); + if (item.isDisable2()) mDisable2Map.put(item.getFlag(), preference); + mDisableMap.put(item.getFlag(), preference); + } + + // Disable not supported prebuilt preferences + Log.d(TAG, "Showed items: " + showedKeys.toString()); + setNotAvailableBatch(showedKeys, getPreferenceScreen()); + } catch (Exception e) { + Log.e(TAG, "Read available disable items", e); + } + SharedPreferences preferences = requireContext().getSharedPreferences("flags", Context.MODE_PRIVATE); + try { + mService.disable(preferences.getInt("disable_flags", mService.getDisableNoneFlag(false))); + updateUIDisabled(false, mService.getDisableFlags()); + } catch (RemoteException e) { + Log.e(TAG, "Receive disable flags", e); + } + + try { + mService.disable2(preferences.getInt("disable2_flags", mService.getDisableNoneFlag(true))); + updateUIDisabled(true, mService.getDisableFlags()); + } catch (RemoteException e) { + Log.e(TAG, "Receive disable2 flags", e); + } + } + + if (mStatusPreference != null) { + mStatusPreference.setEnabled(true); + mStatusPreference.setSummary(enable + ? R.string.status_started : R.string.main_service_status_summary); + } + }); + } + + private void updateUIDisabled(boolean disable2, int flags) { + SparseArray<SwitchPreference> map = + disable2 ? mDisable2Map : mDisableMap; + for (int i = 0; i < map.size(); i ++) { + int flag = map.keyAt(i); + SwitchPreference preference = map.get(flag); + if (preference == null) // Not supported + continue; + preference.setChecked((flags & flag) != 0); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + mReceiver.setContext(requireContext()); + mService = mReceiver.getIPC(); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + runRestoreBinder(savedInstanceState); + } + + private void runRestoreBinder (@Nullable Bundle savedInstanceState) { + if (BuildConfig.DEBUG) { + if (savedInstanceState == null) { + Log.d(TAG, "savedInstanceState is null"); + } else { + if (savedInstanceState.getBinder(ARG_SERVICE) == null) + Log.d(TAG, "savedInstanceState doesn't contain binder"); + else + Log.d(TAG, "Restoring"); + } + } + if (savedInstanceState != null && savedInstanceState.getBinder(ARG_SERVICE) != null) { + // FIXME: 11/25/18 The restoried interface's binder not alive + mService = IStatusController.Stub.asInterface(savedInstanceState.getBinder(ARG_SERVICE)); + } + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + menu.add(0, 0, 0, com.google.android.gms.oss.licenses.R.string.oss_license_title); + menu.add(0, 1, 0, R.string.about_view_in_play_store); + menu.add(0, 2, 0, R.string.about_title); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case 0: + startActivity(new Intent(getActivity(), OssLicensesMenuActivity.class)); + return true; + case 1: + try { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + BuildConfig.APPLICATION_ID)) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + } catch (ActivityNotFoundException ignored) {} + return true; + case 2: + new VersionDialogFragment() + .show(getChildFragmentManager(), "Version"); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onDestroy() { + mReceiver.release(); + // Shell will be closed immediately after executing. + if (mShell != null) mShell.close(); + super.onDestroy(); + } + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + setPreferencesFromResource(R.xml.main_settings, rootKey); + mStatusPreference = findPreference("key_service_status"); + mStatusPreference.setOnPreferenceClickListener(this); + mGroupsShouldBeDisabledBeforeServer.add((PreferenceCategory) findPreference("key_status_bar")); + mGroupsShouldBeDisabledBeforeServer.add((PreferenceCategory) findPreference("key_notification")); + mGroupsShouldBeDisabledBeforeServer.add((PreferenceCategory) findPreference("key_navigation_bar")); + mGroupsShouldBeDisabledBeforeServer.add((PreferenceCategory) findPreference("key_quick_settings")); + mGroupsShouldBeDisabledBeforeServer.add((PreferenceCategory) findPreference("key_other")); + mDisable2Map = new SparseArray<>(5); + mDisableMap = new SparseArray<>(7); + } + + private boolean runDisable (int flag, boolean enable, String name, boolean disable2) { + if (obtainService() == null) return false; + Log.i(TAG, "runDisable: " + flag + " " + enable + " (" + name + ") " + disable2); + try { + int flags = disable2 ? mService.getDisable2Flags() : mService.getDisableFlags(); + if (enable) { + flags |= flag; + } else { + flags ^= flag; + } + if (disable2) { + mService.disable2(flags); + } else { + mService.disable(flags); + } + serializeDisableFlags(); + return true; + } catch (RemoteException e) { + Log.e(TAG, "disable " + name, e); + return false; + } + } + + private void setNotAvailable(@NonNull Preference preference) { + preference.setEnabled(false); + preference.setSummary(R.string.not_available); + } + + @Override + public boolean onPreferenceClick(Preference preference) { + switch (preference.getKey()) { + case "key_service_status": { + boolean shouldStart = obtainService() == null; + mStatusPreference.setEnabled(false); + mStatusPreference.setSummary(shouldStart ? R.string.status_starting : R.string.status_stopping); + if (shouldStart) { + mShell = new Shell.Builder() + .useSU() + .open(this); // Will start after shell opening + } else { + try { + mService.exit(); + } catch (RemoteException ignored) { + } + } + return true; + } + } + return false; + } + + @Override + public void onCommandResult(int commandCode, int exitCode, List<String> output) { + Log.i(TAG, "Result " + commandCode + ": " + exitCode); + if (output != null) { + Log.w(TAG, output.toString()); + } + switch (commandCode) { + case SHELL_RUNNING: + if (exitCode != 0) { + Toast.makeText(getContext(), R.string.error_can_not_open_shell, Toast.LENGTH_LONG).show(); + postStatusUpdate(); // Return status to not started + break; + } + mShell.addCommand(RootDaemon.getLaunchScript(requireContext(), + ControllerService.class, + null, + null, + null, BuildConfig.APPLICATION_ID + ":daemon"), + CODE_START, this); + break; + case CODE_START: + // Kill process immediately + mShell.kill(); + mShell.close(); + mShell = null; + if (exitCode != 0) Toast.makeText(getContext(), R.string.error_can_not_start, Toast.LENGTH_LONG).show(); + break; + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (obtainService() != null) + outState.putBinder(ARG_SERVICE, mService.asBinder()); + } + + private IStatusController obtainService () { + if (!mReceiver.isConnected()) { // TODO: Add instance state support + mService = null; + return null; + } + mService = mReceiver.getIPC(); + return mService; + } +}
\ No newline at end of file diff --git a/app/src/main/java/moe/yuuta/sysuicontroller/about/VersionDialogFragment.java b/app/src/main/java/moe/yuuta/sysuicontroller/about/VersionDialogFragment.java new file mode 100644 index 0000000..20f193d --- /dev/null +++ b/app/src/main/java/moe/yuuta/sysuicontroller/about/VersionDialogFragment.java @@ -0,0 +1,23 @@ +package moe.yuuta.sysuicontroller.about; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; +import moe.yuuta.sysuicontroller.BuildConfig; +import moe.yuuta.sysuicontroller.R; + +public class VersionDialogFragment extends DialogFragment { + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_about, container, false); + ((TextView) view.findViewById(R.id.text_version)).setText(getString(R.string.about_version, BuildConfig.VERSION_NAME)); + return view; + } +} diff --git a/app/src/main/java/moe/yuuta/sysuicontroller/auto_start/AutoStartReceiver.java b/app/src/main/java/moe/yuuta/sysuicontroller/auto_start/AutoStartReceiver.java new file mode 100644 index 0000000..bce97b0 --- /dev/null +++ b/app/src/main/java/moe/yuuta/sysuicontroller/auto_start/AutoStartReceiver.java @@ -0,0 +1,24 @@ +package moe.yuuta.sysuicontroller.auto_start; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import androidx.work.Constraints; +import androidx.work.ExistingWorkPolicy; +import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkManager; +import moe.yuuta.sysuicontroller.BuildConfig; + +public class AutoStartReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + Log.d(AutoStartWorker.class.getSimpleName(), "Received " + intent.getAction()); + WorkManager.getInstance() + .beginUniqueWork(BuildConfig.APPLICATION_ID + ":auto_start", + ExistingWorkPolicy.KEEP, + new OneTimeWorkRequest.Builder(AutoStartWorker.class).setConstraints(Constraints.NONE) + .build()).enqueue(); + } +} diff --git a/app/src/main/java/moe/yuuta/sysuicontroller/auto_start/AutoStartWorker.java b/app/src/main/java/moe/yuuta/sysuicontroller/auto_start/AutoStartWorker.java new file mode 100644 index 0000000..650eeb3 --- /dev/null +++ b/app/src/main/java/moe/yuuta/sysuicontroller/auto_start/AutoStartWorker.java @@ -0,0 +1,76 @@ +package moe.yuuta.sysuicontroller.auto_start; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.RemoteException; +import android.util.Log; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import androidx.annotation.NonNull; +import androidx.work.Worker; +import androidx.work.WorkerParameters; +import eu.chainfire.librootjava.RootIPCReceiver; +import eu.chainfire.librootjavadaemon.RootDaemon; +import eu.chainfire.libsuperuser.Shell; +import moe.yuuta.sysuicontroller.BuildConfig; +import moe.yuuta.sysuicontroller.IStatusController; +import moe.yuuta.sysuicontroller.core.ControllerService; + +public class AutoStartWorker extends Worker { + private static final String TAG = AutoStartWorker.class.getSimpleName(); + + public AutoStartWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); + } + + private CountDownLatch countDownLatch; + + private RootIPCReceiver<IStatusController> mReceiver = new RootIPCReceiver<IStatusController>(null, ControllerService.CODE_SERVICE) { + @Override + public void onConnect(IStatusController ipc) { + try { + SharedPreferences preferences = getApplicationContext().getSharedPreferences("flags", Context.MODE_PRIVATE); + ipc.disable(preferences.getInt("disable_flags", ipc.getDisableFlags())); + ipc.disable2(preferences.getInt("disable2_flags", ipc.getDisable2Flags())); + Log.i(TAG, "Settings restored"); + } catch (RemoteException e) { + Log.e(TAG, "Unable to restore settings", e); + } + countDownLatch.countDown(); + } + + @Override + public void onDisconnect(IStatusController ipc) { + + } + }; + + @NonNull + @Override + public Result doWork() { + Log.i(TAG, "Start auto starting"); + countDownLatch = new CountDownLatch(1); + mReceiver.setContext(getApplicationContext()); + List<String> commands = RootDaemon.getLaunchScript(getApplicationContext(), + ControllerService.class, + null, + null, + null, BuildConfig.APPLICATION_ID + ":daemon"); + if (BuildConfig.DEBUG) Log.d(TAG, commands.toString()); + Shell.Interactive shell = new Shell.Builder().useSU().open(); + shell.addCommand(commands); + try { + countDownLatch.await(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Log.e(TAG, "await()", e); + } + Log.i(TAG, "Done, releasing receiver"); + mReceiver.release(); + shell.kill(); // Kill the process, will make it idle and it won't kill the forked process + shell.close(); + return Result.SUCCESS; + } +} diff --git a/app/src/main/java/moe/yuuta/sysuicontroller/core/ControllerService.java b/app/src/main/java/moe/yuuta/sysuicontroller/core/ControllerService.java new file mode 100644 index 0000000..0574fb4 --- /dev/null +++ b/app/src/main/java/moe/yuuta/sysuicontroller/core/ControllerService.java @@ -0,0 +1,164 @@ +package moe.yuuta.sysuicontroller.core; + +import android.annotation.SuppressLint; +import android.app.StatusBarManager; +import android.content.Context; +import android.os.Binder; +import android.os.Looper; +import android.os.RemoteException; +import android.util.Log; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import eu.chainfire.librootjava.RootIPC; +import eu.chainfire.librootjava.RootJava; +import eu.chainfire.librootjavadaemon.RootDaemon; +import moe.yuuta.sysuicontroller.BuildConfig; +import moe.yuuta.sysuicontroller.IStatusController; + +import static moe.yuuta.sysuicontroller.Main.GLOBAL_TAG; + +public class ControllerService extends IStatusController.Stub { + private static final String TAG = GLOBAL_TAG + ".ControllerService"; + + private int disableFlags = StatusBarManager.DISABLE_NONE; + private int disable2Flags = StatusBarManager.DISABLE2_NONE; + + public static final int CODE_SERVICE = 0; + private StatusBarManager mManager; + private Context mContext; + + public static void main (String... args) throws Throwable { + new ControllerService().run(args); + } + + @SuppressLint("WrongConstant") + private void run (String... args) throws Throwable { + Looper.prepare(); + mContext = RootJava.getSystemContext(); + mManager = (StatusBarManager) mContext.getSystemService("statusbar"); + RootDaemon.daemonize(BuildConfig.APPLICATION_ID, CODE_SERVICE); + RootJava.restoreOriginalLdLibraryPath(); + RootDaemon.register(BuildConfig.APPLICATION_ID, this, CODE_SERVICE); + Log.i(TAG, "Started at " + new Date().toString()); + try { + new RootIPC(BuildConfig.APPLICATION_ID, this, CODE_SERVICE, + 10 * 1000, + true); + } catch (RootIPC.TimeoutException e) { + Log.e(TAG, "Unable to establish a connection, exiting", e); + throw e; + } + RootDaemon.run(); + Log.i(TAG, "Stopped at " + new Date().toString()); + } + + private void enforcePermission () throws SecurityException { + mContext.enforcePermission(BuildConfig.APPLICATION_ID + ".SERVICE", + Binder.getCallingPid(), Binder.getCallingUid(), "Permission denial"); + } + + @Override + public void exit () throws RemoteException { + enforcePermission(); + RootDaemon.exit(); + } + + @Override + public void disable(int flags) throws RemoteException { + enforcePermission(); + disableFlags = flags; + mManager.disable(flags); + } + + @Override + public void disable2(int flags) throws RemoteException { + enforcePermission(); + disable2Flags = flags; + mManager.disable2(flags); + } + + @Override + public void expandNotificationsPanel() throws RemoteException { + enforcePermission(); + mManager.expandNotificationsPanel(); + } + + @Override + public void collapsePanels() throws RemoteException { + enforcePermission(); + mManager.collapsePanels(); + } + + @Override + public void expandSettingsPanel(String subPanel) throws RemoteException { + enforcePermission(); + mManager.expandSettingsPanel(subPanel); + } + + @Override + public void setIcon(String slot, int iconId, int iconLevel, String contentDescription) throws RemoteException { + enforcePermission(); + mManager.setIcon(slot, iconId, iconLevel, contentDescription); + } + + @Override + public void removeIcon(String slot) throws RemoteException { + enforcePermission(); + mManager.removeIcon(slot); + } + + @Override + public void setIconVisibility(String slot, boolean visible) throws RemoteException { + enforcePermission(); + mManager.setIconVisibility(slot, visible); + } + + @Override + public int getDisableFlags() throws RemoteException { + enforcePermission(); + return disableFlags; + } + + @Override + public int getDisable2Flags() throws RemoteException { + enforcePermission(); + return disable2Flags; + } + + @Override + public List<DisableItem> getAvailableDisableItems() throws RemoteException { + Field[] fields = StatusBarManager.class.getDeclaredFields(); + if (fields.length <= 0) return Collections.emptyList(); + List<DisableItem> items = new ArrayList<>(fields.length); + for (Field field : fields) { + if (!Modifier.isStatic(field.getModifiers())) continue; + if (!Modifier.isFinal(field.getModifiers())) continue; + if (!Modifier.isPublic(field.getModifiers())) continue; + if (field.getName().equals("DISABLE_MASK") || field.getName().equals("DISABLE2_MASK") + || field.getName().equals("DISABLE_NONE") || field.getName().equals("DISABLE2_NONE")) continue; + try { + if (field.getName().startsWith("DISABLE_")) { + items.add(new DisableItem(field.getInt(null), field.getName(), false)); + continue; + } + if (field.getName().startsWith("DISABLE2_")) { + items.add(new DisableItem(field.getInt(null), field.getName(), true)); + } + } catch (IllegalAccessException e) { + Log.e(TAG, "Unable to access value: " + field.getName(), e); + } + } + return items; + } + + @Override + public int getDisableNoneFlag(boolean disable2) throws RemoteException { + return disable2 ? StatusBarManager.DISABLE2_NONE : StatusBarManager.DISABLE_NONE; + } +} diff --git a/app/src/main/java/moe/yuuta/sysuicontroller/core/DisableItem.java b/app/src/main/java/moe/yuuta/sysuicontroller/core/DisableItem.java new file mode 100644 index 0000000..efb5699 --- /dev/null +++ b/app/src/main/java/moe/yuuta/sysuicontroller/core/DisableItem.java @@ -0,0 +1,82 @@ +package moe.yuuta.sysuicontroller.core; + +import android.os.Parcel; +import android.os.Parcelable; + +public class DisableItem implements Parcelable { + private int flag; + private String key; + private boolean disable2; + + public DisableItem() { + } + + public DisableItem(int flag, String key, boolean disable2) { + this.flag = flag; + this.key = key; + this.disable2 = disable2; + } + + protected DisableItem(Parcel in) { + flag = in.readInt(); + key = in.readString(); + disable2 = in.readByte() != 0; + } + + public static final Creator<DisableItem> CREATOR = new Creator<DisableItem>() { + @Override + public DisableItem createFromParcel(Parcel in) { + return new DisableItem(in); + } + + @Override + public DisableItem[] newArray(int size) { + return new DisableItem[size]; + } + }; + + public int getFlag() { + return flag; + } + + public void setFlag(int flag) { + this.flag = flag; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public boolean isDisable2() { + return disable2; + } + + public void setDisable2(boolean disable2) { + this.disable2 = disable2; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(flag); + dest.writeString(key); + dest.writeByte((byte) (disable2 ? 1 : 0)); + } + + @Override + public String toString() { + return "DisableItem{" + + "flag=" + flag + + ", key='" + key + '\'' + + ", disable2=" + disable2 + + '}'; + } +} |