59 Commits

Author SHA1 Message Date
Jason Monk
e96fa00e19 SysUI Plugin ClassLoader work
Cache ClassLoader by pkg so that Plugins can talk to each other.

Also add some filtering so that only classes from the plugins package
and sub-packages are included in plugin classloaders.

Test: Manual
Change-Id: I42aabb418168d5a5d0581b8133aa93f07cb7e977
2016-09-30 11:34:25 -04:00
TreeHugger Robot
ac27648255 Merge "Extract plugin interface for lockscreen camera button" 2016-09-29 23:15:41 +00:00
TreeHugger Robot
19796dfbc9 Merge "Extract plugin interface for nav bar" 2016-09-29 20:18:02 +00:00
Jason Monk
b59f46fb9b Extract plugin interface for lockscreen camera button
Create an interface so a plugin can replace the intent and icon of
the camera trigger on the lock screen.

Test: Manual
Change-Id: I867ffb10e3b3906ca3903f96309a3ee5ef9e19d9
2016-09-29 14:31:23 -04:00
Jason Monk
197f4db60b Extract plugin interface for nav bar
This allows plugins to create their own or override nav buttons
based on the button spec.

Test: Manual
Change-Id: I11e9a953710ed14bb9c6d9f96027852a737b58ba
2016-09-29 14:19:33 -04:00
Jason Monk
ef0d34d32e 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
2016-09-27 12:41:34 -04:00
Jason Monk
46767b77c0 Extract plugin interface for QS
Users must implement the QSContainer interface to be returned by
a ViewProvider plugin.  The QSContainer must contain a
BaseStatusBarHeader and have the id of quick_settings_container.

Test: Manual
Change-Id: Ibfaa835cad20855a530e4ae142d8a2aeba4a277b
2016-09-27 10:51:20 -04:00
Jason Monk
beda2ddbec Add PluginInflateContainer
PluginInflateContainer extends AutoReinflateContainer, except that
it also uses the plugin interface to allow the view to be swapped
out with something else.

Define an interface or abstract class as follows that includes the
version and action.

public interface MyInterface {
    public static final String ACTION =
            "com.android.systemui.action.PLUGIN_MYINTERFACE";

    public static final int VERSION = 1;

    void myImportantInterface();
}

Then put in a PluginInflateContainer to use and specify the interface
or class that will be implemented as viewType.  The layout specified
will be used by default and whenever a plugin is not present.

<com.android.systemui.PluginInflateContainer
    android:id="@+id/some_id"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout="@layout/my_default_component"
    systemui:viewType="com.android.systemui.plugins.MyInterface" />

Test: Manual
Change-Id: I2ef3fa8dbe344c4635df20056182c1c0b3846fdf
2016-09-20 16:24:00 -04:00
Jason Monk
86bc331889 Plugins for sysui
Why this is safe:
 - To never ever be used in production code, simply for rapid
   prototyping (multiple checks in place)
 - Guarded by signature level permission checks, so only matching
   signed code will be used
 - Any crashing plugins are auto-disabled and sysui is allowed
   to continue in peace

Now on to what it actually does.  Plugins are separate APKs that
are expected to implement interfaces provided by SystemUI.  Their
code is dynamically loaded into the SysUI process which can allow
for multiple prototypes to be created and run on a single android
build.

-------

PluginLifecycle:

plugin.onCreate(Context sysuiContext, Context pluginContext);
 --- This is always called before any other calls

pluginListener.onPluginConnected(Plugin p);
 --- This lets the plugin hook know that a plugin is now connected.

** Any other calls back and forth between sysui/plugin **

pluginListener.onPluginDisconnected(Plugin p);
 --- Lets the plugin hook know that it should stop interacting with
     this plugin and drop all references to it.

plugin.onDestroy();
 --- Finally the plugin can perform any cleanup to ensure that its not
     leaking into the SysUI process.

Any time a plugin APK is updated the plugin is destroyed and recreated
to load the new code/resources.

-------

Creating plugin hooks:

To create a plugin hook, first create an interface in
frameworks/base/packages/SystemUI/plugin that extends Plugin.
Include in it any hooks you want to be able to call into from
sysui and create callback interfaces for anything you need to
pass through into the plugin.

Then to attach to any plugins simply add a plugin listener and
onPluginConnected will get called whenever new plugins are installed,
updated, or enabled.  Like this example from SystemUIApplication:

PluginManager.getInstance(this).addPluginListener(OverlayPlugin.COMPONENT,
        new PluginListener<OverlayPlugin>() {
    @Override
    public void onPluginConnected(OverlayPlugin plugin) {
        PhoneStatusBar phoneStatusBar = getComponent(PhoneStatusBar.class);
        if (phoneStatusBar != null) {
            plugin.setup(phoneStatusBar.getStatusBarWindow(),
                    phoneStatusBar.getNavigationBarView());
        }
    }
}, OverlayPlugin.VERSION, true /* Allow multiple plugins */);

Note the VERSION included here.  Any time incompatible changes in the
interface are made, this version should be changed to ensure old plugins
aren't accidentally loaded.  Since the plugin library is provided by
SystemUI, default implementations can be added for new methods to avoid
version changes when possible.

-------

Implementing a Plugin:

See the ExamplePlugin for an example Android.mk on how to compile
a plugin.  Note that SystemUILib is not static for plugins, its classes
are provided by SystemUI.

Plugin security is based around a signature permission, so plugins must
hold the following permission in their manifest.

<uses-permission android:name="com.android.systemui.permission.PLUGIN" />

A plugin is found through a querying for services, so to let SysUI know
about it, create a service with a name that points at your implementation
of the plugin interface with the action accompanying it:

<service android:name=".TestOverlayPlugin">
    <intent-filter>
        <action android:name="com.android.systemui.action.PLUGIN_COMPONENT" />
    </intent-filter>
</service>

Change-Id: I42c573a94907ca7a2eaacbb0a44614d49b8fc26f
2016-09-02 11:33:22 -04:00