Add plugin controls to tuner
Allow plugins to be manually turned off from within the tuner. This screen only shows itself if at some point in time a plugin has been active on this device. Plugins can also serface settings there by receiving the com.android.systemui.action.PLUGIN_SETTINGS action. Test: Manual Change-Id: Ifb043c85e383fc072c6445ae322293a6401a6f2c
This commit is contained in:
@@ -21,7 +21,15 @@
|
||||
<uses-permission android:name="com.android.systemui.permission.PLUGIN" />
|
||||
|
||||
<application>
|
||||
<service android:name=".SampleOverlayPlugin">
|
||||
<activity android:name=".PluginSettings"
|
||||
android:label="@string/plugin_label">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.systemui.action.PLUGIN_SETTINGS" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service android:name=".SampleOverlayPlugin"
|
||||
android:label="@string/plugin_label">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.systemui.action.PLUGIN_OVERLAY" />
|
||||
</intent-filter>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
** Copyright 2016, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
-->
|
||||
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:text="@string/plugin_settings_here"
|
||||
android:gravity="center" />
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/**
|
||||
* Copyright (c) 2016, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
-->
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
|
||||
<string name="plugin_settings_here" translatable="false">Plugin settings go here</string>
|
||||
<string name="plugin_label" translatable="false">Overlay Plugin</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.plugin.testoverlayplugin;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
* DO NOT Reference Plugin interfaces here, this runs in the plugin APK's process
|
||||
* and is only for modifying settings.
|
||||
*/
|
||||
public class PluginSettings extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.plugin_settings);
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
@@ -163,6 +162,7 @@ public class PluginInstanceManager<T extends Plugin> extends BroadcastReceiver {
|
||||
switch (msg.what) {
|
||||
case PLUGIN_CONNECTED:
|
||||
if (DEBUG) Log.d(TAG, "onPluginConnected");
|
||||
PluginPrefs.setHasPlugins(mContext);
|
||||
PluginInfo<T> info = (PluginInfo<T>) msg.obj;
|
||||
info.mPlugin.onCreate(mContext, info.mPluginContext);
|
||||
mListener.onPluginConnected(info.mPlugin);
|
||||
|
||||
@@ -37,6 +37,7 @@ public class PluginManager {
|
||||
private final Context mContext;
|
||||
private final PluginInstanceManagerFactory mFactory;
|
||||
private final boolean isDebuggable;
|
||||
private final PluginPrefs mPluginPrefs;
|
||||
|
||||
private PluginManager(Context context) {
|
||||
this(context, new PluginInstanceManagerFactory(), Build.IS_DEBUGGABLE,
|
||||
@@ -51,6 +52,7 @@ public class PluginManager {
|
||||
mBackgroundThread = new HandlerThread("Plugins");
|
||||
mBackgroundThread.start();
|
||||
isDebuggable = debuggable;
|
||||
mPluginPrefs = new PluginPrefs(mContext);
|
||||
|
||||
PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(
|
||||
defaultHandler);
|
||||
@@ -68,6 +70,7 @@ public class PluginManager {
|
||||
// Never ever ever allow these on production builds, they are only for prototyping.
|
||||
return;
|
||||
}
|
||||
mPluginPrefs.addAction(action);
|
||||
PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,
|
||||
allowMultiple, mBackgroundThread.getLooper(), version);
|
||||
p.startListening();
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.plugins;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Storage for all plugin actions in SharedPreferences.
|
||||
*
|
||||
* This allows the list of actions that the Tuner needs to search for to be generated
|
||||
* instead of hard coded.
|
||||
*/
|
||||
public class PluginPrefs {
|
||||
|
||||
private static final String PREFS = "plugin_prefs";
|
||||
|
||||
private static final String PLUGIN_ACTIONS = "actions";
|
||||
private static final String HAS_PLUGINS = "plugins";
|
||||
|
||||
private final Set<String> mPluginActions;
|
||||
private final SharedPreferences mSharedPrefs;
|
||||
|
||||
public PluginPrefs(Context context) {
|
||||
mSharedPrefs = context.getSharedPreferences(PREFS, 0);
|
||||
mPluginActions = new ArraySet<>(mSharedPrefs.getStringSet(PLUGIN_ACTIONS, null));
|
||||
}
|
||||
|
||||
public Set<String> getPluginList() {
|
||||
return mPluginActions;
|
||||
}
|
||||
|
||||
public synchronized void addAction(String action) {
|
||||
if (mPluginActions.add(action)){
|
||||
mSharedPrefs.edit().putStringSet(PLUGIN_ACTIONS, mPluginActions).commit();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasPlugins(Context context) {
|
||||
return context.getSharedPreferences(PREFS, 0).getBoolean(HAS_PLUGINS, false);
|
||||
}
|
||||
|
||||
public static void setHasPlugins(Context context) {
|
||||
context.getSharedPreferences(PREFS, 0).edit().putBoolean(HAS_PLUGINS, true).commit();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2016 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/settings"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_settings"
|
||||
android:tint="@android:color/black"
|
||||
android:padding="12dp"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless" />
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="?android:attr/listDivider" />
|
||||
|
||||
<Switch
|
||||
android:id="@android:id/switch_widget"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusable="false"
|
||||
android:clickable="false"
|
||||
android:background="@null" />
|
||||
</LinearLayout>
|
||||
@@ -1667,4 +1667,8 @@
|
||||
<!-- accessibility label for paging indicator in quick settings [CHAR LIMITi=NONE] -->
|
||||
<string name="accessibility_quick_settings_page">Page <xliff:g name="current_page" example="1">%1$d</xliff:g> of <xliff:g name="num_pages" example="2">%2$d</xliff:g></string>
|
||||
|
||||
<!-- Plugin control section of the tuner. Non-translatable since it should
|
||||
not appear on production builds ever. -->
|
||||
<string name="plugins" translatable="false">Plugins</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -133,6 +133,11 @@
|
||||
android:title="@string/other"
|
||||
android:fragment="com.android.systemui.tuner.OtherPrefs" />
|
||||
|
||||
<Preference
|
||||
android:key="plugins"
|
||||
android:title="@string/plugins"
|
||||
android:fragment="com.android.systemui.tuner.PluginFragment" />
|
||||
|
||||
<!-- Warning, this goes last. -->
|
||||
<Preference
|
||||
android:summary="@string/tuner_persistent_warning"
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.tuner;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Bundle;
|
||||
import android.support.v14.preference.PreferenceFragment;
|
||||
import android.support.v14.preference.SwitchPreference;
|
||||
import android.support.v7.preference.PreferenceCategory;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
import android.support.v7.preference.PreferenceViewHolder;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.systemui.plugins.PluginPrefs;
|
||||
import com.android.systemui.R;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class PluginFragment extends PreferenceFragment {
|
||||
|
||||
public static final String ACTION_PLUGIN_SETTINGS
|
||||
= "com.android.systemui.action.PLUGIN_SETTINGS";
|
||||
|
||||
private PluginPrefs mPluginPrefs;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getContext());
|
||||
screen.setOrderingAsAdded(false);
|
||||
Context prefContext = getPreferenceManager().getContext();
|
||||
mPluginPrefs = new PluginPrefs(getContext());
|
||||
Set<String> pluginActions = mPluginPrefs.getPluginList();
|
||||
for (String action : pluginActions) {
|
||||
String name = action.replace("com.android.systemui.action.PLUGIN_", "");
|
||||
PreferenceCategory category = new PreferenceCategory(prefContext);
|
||||
category.setTitle(name);
|
||||
|
||||
List<ResolveInfo> result = getContext().getPackageManager().queryIntentServices(
|
||||
new Intent(action), PackageManager.MATCH_DISABLED_COMPONENTS);
|
||||
if (result.size() > 0) {
|
||||
screen.addPreference(category);
|
||||
}
|
||||
for (ResolveInfo info : result) {
|
||||
category.addPreference(new PluginPreference(prefContext, info));
|
||||
}
|
||||
}
|
||||
setPreferenceScreen(screen);
|
||||
}
|
||||
|
||||
private static class PluginPreference extends SwitchPreference {
|
||||
private final ComponentName mComponent;
|
||||
private final boolean mHasSettings;
|
||||
|
||||
public PluginPreference(Context prefContext, ResolveInfo info) {
|
||||
super(prefContext);
|
||||
mComponent = new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);
|
||||
PackageManager pm = prefContext.getPackageManager();
|
||||
mHasSettings = pm.resolveActivity(new Intent(ACTION_PLUGIN_SETTINGS)
|
||||
.setPackage(mComponent.getPackageName()), 0) != null;
|
||||
setTitle(info.serviceInfo.loadLabel(pm));
|
||||
setChecked(pm.getComponentEnabledSetting(mComponent)
|
||||
!= PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
|
||||
setWidgetLayoutResource(R.layout.tuner_widget_settings_switch);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean persistBoolean(boolean value) {
|
||||
getContext().getPackageManager().setComponentEnabledSetting(mComponent,
|
||||
value ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|
||||
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
||||
PackageManager.DONT_KILL_APP);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
holder.findViewById(R.id.settings).setVisibility(mHasSettings ? View.VISIBLE
|
||||
: View.GONE);
|
||||
holder.findViewById(R.id.divider).setVisibility(mHasSettings ? View.VISIBLE
|
||||
: View.GONE);
|
||||
holder.findViewById(R.id.settings).setOnClickListener(v -> {
|
||||
ResolveInfo result = v.getContext().getPackageManager().resolveActivity(
|
||||
new Intent(ACTION_PLUGIN_SETTINGS).setPackage(
|
||||
mComponent.getPackageName()), 0);
|
||||
if (result != null) {
|
||||
v.getContext().startActivity(new Intent().setComponent(
|
||||
new ComponentName(result.activityInfo.packageName,
|
||||
result.activityInfo.name)));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,16 +19,9 @@ import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.content.DialogInterface;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.System;
|
||||
import android.support.v14.preference.PreferenceFragment;
|
||||
import android.support.v14.preference.SwitchPreference;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
@@ -36,12 +29,14 @@ import android.view.MenuItem;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.MetricsProto.MetricsEvent;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.plugins.PluginPrefs;
|
||||
|
||||
public class TunerFragment extends PreferenceFragment {
|
||||
|
||||
private static final String TAG = "TunerFragment";
|
||||
|
||||
private static final String KEY_BATTERY_PCT = "battery_pct";
|
||||
private static final String KEY_PLUGINS = "plugins";
|
||||
|
||||
public static final String SETTING_SEEN_TUNER_WARNING = "seen_tuner_warning";
|
||||
|
||||
@@ -65,6 +60,9 @@ public class TunerFragment extends PreferenceFragment {
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.tuner_prefs);
|
||||
if (!PluginPrefs.hasPlugins(getContext())) {
|
||||
getPreferenceScreen().removePreference(findPreference(KEY_PLUGINS));
|
||||
}
|
||||
|
||||
if (Settings.Secure.getInt(getContext().getContentResolver(), SETTING_SEEN_TUNER_WARNING,
|
||||
0) == 0) {
|
||||
|
||||
Reference in New Issue
Block a user