Merge "Remove custom MainHandler from PluginInstanceManager" into sc-v2-dev am: b325b69f12

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15478379

Change-Id: Ieb36b3dba8ef2ed7a624da81d37814bee6011286
This commit is contained in:
Dave Mankoff
2021-08-16 15:22:34 +00:00
committed by Automerger Merge Worker
9 changed files with 95 additions and 189 deletions

View File

@@ -45,6 +45,7 @@ import com.android.systemui.shared.plugins.VersionInfo.InvalidVersionException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor;
public class PluginInstanceManager<T extends Plugin> { public class PluginInstanceManager<T extends Plugin> {
@@ -59,8 +60,6 @@ public class PluginInstanceManager<T extends Plugin> {
private final boolean mAllowMultiple; private final boolean mAllowMultiple;
private final VersionInfo mVersion; private final VersionInfo mVersion;
@VisibleForTesting
final MainHandler mMainHandler;
@VisibleForTesting @VisibleForTesting
final PluginHandler mPluginHandler; final PluginHandler mPluginHandler;
private final boolean isDebuggable; private final boolean isDebuggable;
@@ -68,13 +67,14 @@ public class PluginInstanceManager<T extends Plugin> {
private final PluginManagerImpl mManager; private final PluginManagerImpl mManager;
private final ArraySet<String> mWhitelistedPlugins = new ArraySet<>(); private final ArraySet<String> mWhitelistedPlugins = new ArraySet<>();
private final PluginInitializer mInitializer; private final PluginInitializer mInitializer;
private final Executor mMainExecutor;
PluginInstanceManager(Context context, PackageManager pm, String action, PluginInstanceManager(Context context, PackageManager pm, String action,
PluginListener<T> listener, boolean allowMultiple, Looper looper, VersionInfo version, PluginListener<T> listener, boolean allowMultiple, Executor mainExecutor,
PluginManagerImpl manager, boolean debuggable, String[] pluginWhitelist, Looper looper, VersionInfo version, PluginManagerImpl manager, boolean debuggable,
PluginInitializer initializer) { String[] pluginWhitelist, PluginInitializer initializer) {
mInitializer = initializer; mInitializer = initializer;
mMainHandler = new MainHandler(Looper.getMainLooper()); mMainExecutor = mainExecutor;
mPluginHandler = new PluginHandler(looper); mPluginHandler = new PluginHandler(looper);
mManager = manager; mManager = manager;
mContext = context; mContext = context;
@@ -87,21 +87,6 @@ public class PluginInstanceManager<T extends Plugin> {
isDebuggable = debuggable; isDebuggable = debuggable;
} }
public PluginInfo<T> getPlugin() {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new RuntimeException("Must be called from UI thread");
}
mPluginHandler.handleQueryPlugins(null /* All packages */);
if (mPluginHandler.mPlugins.size() > 0) {
mMainHandler.removeMessages(MainHandler.PLUGIN_CONNECTED);
PluginInfo<T> info = mPluginHandler.mPlugins.get(0);
PluginPrefs.setHasPlugins(mContext);
info.mPlugin.onCreate(mContext, info.mPluginContext);
return info;
}
return null;
}
public void loadAll() { public void loadAll() {
if (DEBUG) Log.d(TAG, "startListening"); if (DEBUG) Log.d(TAG, "startListening");
mPluginHandler.sendEmptyMessage(PluginHandler.QUERY_ALL); mPluginHandler.sendEmptyMessage(PluginHandler.QUERY_ALL);
@@ -109,10 +94,9 @@ public class PluginInstanceManager<T extends Plugin> {
public void destroy() { public void destroy() {
if (DEBUG) Log.d(TAG, "stopListening"); if (DEBUG) Log.d(TAG, "stopListening");
ArrayList<PluginInfo> plugins = new ArrayList<PluginInfo>(mPluginHandler.mPlugins); ArrayList<PluginInfo<T>> plugins = new ArrayList<>(mPluginHandler.mPlugins);
for (PluginInfo plugin : plugins) { for (PluginInfo<T> pluginInfo : plugins) {
mMainHandler.obtainMessage(MainHandler.PLUGIN_DISCONNECTED, mMainExecutor.execute(() -> onPluginDisconnected(pluginInfo.mPlugin));
plugin.mPlugin).sendToTarget();
} }
} }
@@ -127,8 +111,8 @@ public class PluginInstanceManager<T extends Plugin> {
public boolean checkAndDisable(String className) { public boolean checkAndDisable(String className) {
boolean disableAny = false; boolean disableAny = false;
ArrayList<PluginInfo> plugins = new ArrayList<PluginInfo>(mPluginHandler.mPlugins); ArrayList<PluginInfo<T>> plugins = new ArrayList<>(mPluginHandler.mPlugins);
for (PluginInfo info : plugins) { for (PluginInfo<T> info : plugins) {
if (className.startsWith(info.mPackage)) { if (className.startsWith(info.mPackage)) {
disableAny |= disable(info, PluginEnabler.DISABLED_FROM_EXPLICIT_CRASH); disableAny |= disable(info, PluginEnabler.DISABLED_FROM_EXPLICIT_CRASH);
} }
@@ -137,7 +121,7 @@ public class PluginInstanceManager<T extends Plugin> {
} }
public boolean disableAll() { public boolean disableAll() {
ArrayList<PluginInfo> plugins = new ArrayList<PluginInfo>(mPluginHandler.mPlugins); ArrayList<PluginInfo<T>> plugins = new ArrayList<>(mPluginHandler.mPlugins);
boolean disabledAny = false; boolean disabledAny = false;
for (int i = 0; i < plugins.size(); i++) { for (int i = 0; i < plugins.size(); i++) {
disabledAny |= disable(plugins.get(i), PluginEnabler.DISABLED_FROM_SYSTEM_CRASH); disabledAny |= disable(plugins.get(i), PluginEnabler.DISABLED_FROM_SYSTEM_CRASH);
@@ -161,7 +145,7 @@ public class PluginInstanceManager<T extends Plugin> {
return false; return false;
} }
private boolean disable(PluginInfo info, @PluginEnabler.DisableReason int reason) { private boolean disable(PluginInfo<T> info, @PluginEnabler.DisableReason int reason) {
// Live by the sword, die by the sword. // Live by the sword, die by the sword.
// Misbehaving plugins get disabled and won't come back until uninstall/reinstall. // Misbehaving plugins get disabled and won't come back until uninstall/reinstall.
@@ -179,9 +163,9 @@ public class PluginInstanceManager<T extends Plugin> {
return true; return true;
} }
public <T> boolean dependsOn(Plugin p, Class<T> cls) { <C> boolean dependsOn(Plugin p, Class<C> cls) {
ArrayList<PluginInfo> plugins = new ArrayList<PluginInfo>(mPluginHandler.mPlugins); ArrayList<PluginInfo<T>> plugins = new ArrayList<>(mPluginHandler.mPlugins);
for (PluginInfo info : plugins) { for (PluginInfo<T> info : plugins) {
if (info.mPlugin.getClass().getName().equals(p.getClass().getName())) { if (info.mPlugin.getClass().getName().equals(p.getClass().getName())) {
return info.mVersion != null && info.mVersion.hasClass(cls); return info.mVersion != null && info.mVersion.hasClass(cls);
} }
@@ -195,42 +179,25 @@ public class PluginInstanceManager<T extends Plugin> {
getClass().getSimpleName(), hashCode(), mAction); getClass().getSimpleName(), hashCode(), mAction);
} }
private class MainHandler extends Handler { private void onPluginConnected(PluginInfo<T> pluginInfo) {
private static final int PLUGIN_CONNECTED = 1;
private static final int PLUGIN_DISCONNECTED = 2;
public MainHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case PLUGIN_CONNECTED:
if (DEBUG) Log.d(TAG, "onPluginConnected"); if (DEBUG) Log.d(TAG, "onPluginConnected");
PluginPrefs.setHasPlugins(mContext); PluginPrefs.setHasPlugins(mContext);
PluginInfo<T> info = (PluginInfo<T>) msg.obj;
mInitializer.handleWtfs(); mInitializer.handleWtfs();
if (!(msg.obj instanceof PluginFragment)) { if (!(pluginInfo.mPlugin instanceof PluginFragment)) {
// Only call onDestroy for plugins that aren't fragments, as fragments // Only call onCreate for plugins that aren't fragments, as fragments
// will get the onCreate as part of the fragment lifecycle. // will get the onCreate as part of the fragment lifecycle.
info.mPlugin.onCreate(mContext, info.mPluginContext); pluginInfo.mPlugin.onCreate(mContext, pluginInfo.mPluginContext);
} }
mListener.onPluginConnected(info.mPlugin, info.mPluginContext); mListener.onPluginConnected(pluginInfo.mPlugin, pluginInfo.mPluginContext);
break; }
case PLUGIN_DISCONNECTED:
private void onPluginDisconnected(T plugin) {
if (DEBUG) Log.d(TAG, "onPluginDisconnected"); if (DEBUG) Log.d(TAG, "onPluginDisconnected");
mListener.onPluginDisconnected((T) msg.obj); mListener.onPluginDisconnected(plugin);
if (!(msg.obj instanceof PluginFragment)) { if (!(plugin instanceof PluginFragment)) {
// Only call onDestroy for plugins that aren't fragments, as fragments // Only call onDestroy for plugins that aren't fragments, as fragments
// will get the onDestroy as part of the fragment lifecycle. // will get the onDestroy as part of the fragment lifecycle.
((T) msg.obj).onDestroy(); plugin.onDestroy();
}
break;
default:
super.handleMessage(msg);
break;
}
} }
} }
@@ -252,8 +219,7 @@ public class PluginInstanceManager<T extends Plugin> {
if (DEBUG) Log.d(TAG, "queryAll " + mAction); if (DEBUG) Log.d(TAG, "queryAll " + mAction);
for (int i = mPlugins.size() - 1; i >= 0; i--) { for (int i = mPlugins.size() - 1; i >= 0; i--) {
PluginInfo<T> pluginInfo = mPlugins.get(i); PluginInfo<T> pluginInfo = mPlugins.get(i);
mMainHandler.obtainMessage( mMainExecutor.execute(() -> onPluginDisconnected(pluginInfo.mPlugin));
MainHandler.PLUGIN_DISCONNECTED, pluginInfo.mPlugin).sendToTarget();
} }
mPlugins.clear(); mPlugins.clear();
handleQueryPlugins(null); handleQueryPlugins(null);
@@ -261,10 +227,9 @@ public class PluginInstanceManager<T extends Plugin> {
case REMOVE_PKG: case REMOVE_PKG:
String pkg = (String) msg.obj; String pkg = (String) msg.obj;
for (int i = mPlugins.size() - 1; i >= 0; i--) { for (int i = mPlugins.size() - 1; i >= 0; i--) {
final PluginInfo<T> plugin = mPlugins.get(i); final PluginInfo<T> pluginInfo = mPlugins.get(i);
if (plugin.mPackage.equals(pkg)) { if (pluginInfo.mPackage.equals(pkg)) {
mMainHandler.obtainMessage(MainHandler.PLUGIN_DISCONNECTED, mMainExecutor.execute(() -> onPluginDisconnected(pluginInfo.mPlugin));
plugin.mPlugin).sendToTarget();
mPlugins.remove(i); mPlugins.remove(i);
} }
} }
@@ -307,12 +272,12 @@ public class PluginInstanceManager<T extends Plugin> {
for (ResolveInfo info : result) { for (ResolveInfo info : result) {
ComponentName name = new ComponentName(info.serviceInfo.packageName, ComponentName name = new ComponentName(info.serviceInfo.packageName,
info.serviceInfo.name); info.serviceInfo.name);
PluginInfo<T> t = handleLoadPlugin(name); PluginInfo<T> pluginInfo = handleLoadPlugin(name);
if (t == null) continue; if (pluginInfo == null) continue;
// add plugin before sending PLUGIN_CONNECTED message // add plugin before sending PLUGIN_CONNECTED message
mPlugins.add(t); mPlugins.add(pluginInfo);
mMainHandler.obtainMessage(mMainHandler.PLUGIN_CONNECTED, t).sendToTarget(); mMainExecutor.execute(() -> onPluginConnected(pluginInfo));
} }
} }
@@ -349,7 +314,7 @@ public class PluginInstanceManager<T extends Plugin> {
try { try {
VersionInfo version = checkVersion(pluginClass, plugin, mVersion); VersionInfo version = checkVersion(pluginClass, plugin, mVersion);
if (DEBUG) Log.d(TAG, "createPlugin"); if (DEBUG) Log.d(TAG, "createPlugin");
return new PluginInfo(pkg, cls, plugin, pluginContext, version); return new PluginInfo<>(pkg, cls, plugin, pluginContext, version);
} catch (InvalidVersionException e) { } catch (InvalidVersionException e) {
final int icon = Resources.getSystem().getIdentifier( final int icon = Resources.getSystem().getIdentifier(
"stat_sys_warning", "drawable", "android"); "stat_sys_warning", "drawable", "android");
@@ -419,13 +384,15 @@ public class PluginInstanceManager<T extends Plugin> {
public static class Factory { public static class Factory {
private final Context mContext; private final Context mContext;
private final PackageManager mPackageManager; private final PackageManager mPackageManager;
private final Executor mMainExecutor;
private final Looper mLooper; private final Looper mLooper;
private final PluginInitializer mInitializer; private final PluginInitializer mInitializer;
public Factory(Context context, PackageManager packageManager, Looper looper, public Factory(Context context, PackageManager packageManager,
PluginInitializer initializer) { Executor mainExecutor, Looper looper, PluginInitializer initializer) {
mContext = context; mContext = context;
mPackageManager = packageManager; mPackageManager = packageManager;
mMainExecutor = mainExecutor;
mLooper = looper; mLooper = looper;
mInitializer = initializer; mInitializer = initializer;
} }
@@ -435,8 +402,8 @@ public class PluginInstanceManager<T extends Plugin> {
PluginListener<T> listener, boolean allowMultiple, VersionInfo version, PluginListener<T> listener, boolean allowMultiple, VersionInfo version,
PluginManagerImpl manager, boolean debuggable, String[] pluginWhitelist) { PluginManagerImpl manager, boolean debuggable, String[] pluginWhitelist) {
return new PluginInstanceManager<>(mContext, mPackageManager, action, listener, return new PluginInstanceManager<>(mContext, mPackageManager, action, listener,
allowMultiple, mLooper, version, manager, debuggable, pluginWhitelist, allowMultiple, mMainExecutor, mLooper, version, manager, debuggable,
mInitializer); pluginWhitelist, mInitializer);
} }
} }
@@ -466,10 +433,10 @@ public class PluginInstanceManager<T extends Plugin> {
} }
} }
static class PluginInfo<T> { static class PluginInfo<T extends Plugin> {
private final Context mPluginContext; private final Context mPluginContext;
private final VersionInfo mVersion; private final VersionInfo mVersion;
private String mClass; private final String mClass;
T mPlugin; T mPlugin;
String mPackage; String mPackage;

View File

@@ -30,9 +30,6 @@ public interface PluginManager {
/** Returns plugins that don't get disabled when an exceptoin occurs. */ /** Returns plugins that don't get disabled when an exceptoin occurs. */
String[] getPrivilegedPlugins(); String[] getPrivilegedPlugins();
<T extends Plugin> T getOneShotPlugin(Class<T> cls);
<T extends Plugin> T getOneShotPlugin(String action, Class<?> cls);
<T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls); <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls);
<T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls, <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls,
boolean allowMultiple); boolean allowMultiple);

View File

@@ -30,7 +30,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources; import android.content.res.Resources;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Looper;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.ArrayMap; import android.util.ArrayMap;
@@ -41,8 +40,6 @@ import android.widget.Toast;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.annotations.ProvidesInterface;
import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;
import dalvik.system.PathClassLoader; import dalvik.system.PathClassLoader;
@@ -109,38 +106,6 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
return mPluginEnabler; return mPluginEnabler;
} }
// TODO(mankoff): This appears to be only called from tests. Remove?
public <T extends Plugin> T getOneShotPlugin(Class<T> cls) {
ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
if (info == null) {
throw new RuntimeException(cls + " doesn't provide an interface");
}
if (TextUtils.isEmpty(info.action())) {
throw new RuntimeException(cls + " doesn't provide an action");
}
return getOneShotPlugin(info.action(), cls);
}
public <T extends Plugin> T getOneShotPlugin(String action, Class<?> cls) {
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new RuntimeException("Must be called from UI thread");
}
// Passing null causes compiler to complain about incompatible (generic) types.
PluginListener<T> dummy = null;
PluginInstanceManager<T> p = mInstanceManagerFactory.create(
action, dummy, false, new VersionInfo().addClass(cls), this,
isDebuggable(), getPrivilegedPlugins());
mPluginPrefs.addAction(action);
PluginInfo<T> info = p.getPlugin();
if (info != null) {
mOneShotPackages.add(info.mPackage);
mHasOneShot = true;
startListening();
return info.mPlugin;
}
return null;
}
public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls) { public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls) {
addPluginListener(listener, cls, false); addPluginListener(listener, cls, false);
} }

View File

@@ -23,15 +23,18 @@ import android.content.pm.PackageManager;
import android.os.Build; import android.os.Build;
import android.os.Looper; import android.os.Looper;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.shared.plugins.PluginEnabler; import com.android.systemui.shared.plugins.PluginEnabler;
import com.android.systemui.shared.plugins.PluginInitializer; import com.android.systemui.shared.plugins.PluginInitializer;
import com.android.systemui.shared.plugins.PluginInstanceManager; import com.android.systemui.shared.plugins.PluginInstanceManager;
import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.plugins.PluginManagerImpl; import com.android.systemui.shared.plugins.PluginManagerImpl;
import com.android.systemui.shared.plugins.PluginPrefs; import com.android.systemui.shared.plugins.PluginPrefs;
import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
import com.android.systemui.util.concurrency.ThreadFactory; import com.android.systemui.util.concurrency.ThreadFactory;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.Executor;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
@@ -46,7 +49,7 @@ import dagger.Provides;
* Covers code both in com.android.systemui.plugins and code in * Covers code both in com.android.systemui.plugins and code in
* com.android.systemui.shared.plugins. * com.android.systemui.shared.plugins.
*/ */
@Module @Module(includes = {GlobalConcurrencyModule.class})
public abstract class PluginsModule { public abstract class PluginsModule {
public static final String PLUGIN_THREAD = "plugin_thread"; public static final String PLUGIN_THREAD = "plugin_thread";
public static final String PLUGIN_DEBUG = "plugin_debug"; public static final String PLUGIN_DEBUG = "plugin_debug";
@@ -67,10 +70,10 @@ public abstract class PluginsModule {
@Provides @Provides
@Singleton @Singleton
static PluginInstanceManager.Factory providePluginInstanceManagerFactory(Context context, static PluginInstanceManager.Factory providePluginInstanceManagerFactory(Context context,
PackageManager packageManager, @Named(PLUGIN_THREAD) Looper pluginLooper, PackageManager packageManager, @Main Executor mainExecutor,
PluginInitializer initializer) { @Named(PLUGIN_THREAD) Looper pluginLooper, PluginInitializer initializer) {
return new PluginInstanceManager.Factory( return new PluginInstanceManager.Factory(
context, packageManager, pluginLooper, initializer); context, packageManager, mainExecutor, pluginLooper, initializer);
} }
@Provides @Provides

View File

@@ -67,11 +67,23 @@ public abstract class GlobalConcurrencyModule {
* Provide a Main-Thread Executor. * Provide a Main-Thread Executor.
*/ */
@Provides @Provides
@Singleton
@Main @Main
public static Executor provideMainExecutor(Context context) { public static Executor provideMainExecutor(Context context) {
return context.getMainExecutor(); return context.getMainExecutor();
} }
/**
* Provide a Main-Thread DelayableExecutor.
*/
@Provides
@Singleton
@Main
public static DelayableExecutor provideMainDelayableExecutor(@Main Looper looper) {
return new ExecutorImpl(looper);
}
/** */ /** */
@Binds @Binds
@Singleton @Singleton

View File

@@ -119,16 +119,6 @@ public abstract class SysUIConcurrencyModule {
return new ExecutorImpl(looper); return new ExecutorImpl(looper);
} }
/**
* Provide a Main-Thread Executor.
*/
@Provides
@SysUISingleton
@Main
public static DelayableExecutor provideMainDelayableExecutor(@Main Looper looper) {
return new ExecutorImpl(looper);
}
/** /**
* Provide a Background-Thread Executor by default. * Provide a Background-Thread Executor by default.
*/ */

View File

@@ -15,7 +15,6 @@
package com.android.systemui.shared.plugins; package com.android.systemui.shared.plugins;
import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
@@ -42,7 +41,6 @@ import android.content.pm.ServiceInfo;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
import androidx.test.annotation.UiThreadTest;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
@@ -50,8 +48,9 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.annotations.Requires; import com.android.systemui.plugins.annotations.Requires;
import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;
import com.android.systemui.shared.plugins.VersionInfo.InvalidVersionException; import com.android.systemui.shared.plugins.VersionInfo.InvalidVersionException;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@@ -83,6 +82,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
ComponentName mTestPluginComponentName = ComponentName mTestPluginComponentName =
new ComponentName(WHITELISTED_PACKAGE, TestPlugin.class.getName()); new ComponentName(WHITELISTED_PACKAGE, TestPlugin.class.getName());
private PluginInitializer mInitializer; private PluginInitializer mInitializer;
private final FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
@Before @Before
public void setup() throws Exception { public void setup() throws Exception {
@@ -98,8 +98,8 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
mMockVersionInfo = mock(VersionInfo.class); mMockVersionInfo = mock(VersionInfo.class);
mInitializer = mock(PluginInitializer.class); mInitializer = mock(PluginInitializer.class);
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction", mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo, mMockListener, true, mFakeExecutor, mHandlerThread.getLooper(),
mMockManager, true, new String[0], mInitializer); mMockVersionInfo, mMockManager, true, new String[0], mInitializer);
sMockPlugin = mock(Plugin.class); sMockPlugin = mock(Plugin.class);
when(sMockPlugin.getVersion()).thenReturn(1); when(sMockPlugin.getVersion()).thenReturn(1);
} }
@@ -110,23 +110,14 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
sMockPlugin = null; sMockPlugin = null;
} }
@UiThreadTest
@Test @Test
public void testGetPlugin() throws Exception { public void testNoPlugins() {
setupFakePmQuery();
PluginInfo p = mPluginInstanceManager.getPlugin();
assertNotNull(p.mPlugin);
verify(sMockPlugin).onCreate(any(), any());
}
@Test
public void testNoPlugins() throws Exception {
when(mMockPm.queryIntentServices(any(), anyInt())).thenReturn( when(mMockPm.queryIntentServices(any(), anyInt())).thenReturn(
Collections.emptyList()); Collections.emptyList());
mPluginInstanceManager.loadAll(); mPluginInstanceManager.loadAll();
waitForIdleSync(mPluginInstanceManager.mPluginHandler); waitForIdleSync(mPluginInstanceManager.mPluginHandler);
waitForIdleSync(mPluginInstanceManager.mMainHandler); mFakeExecutor.runAllReady();
verify(mMockListener, never()).onPluginConnected(any(), any()); verify(mMockListener, never()).onPluginConnected(any(), any());
} }
@@ -148,7 +139,8 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
mPluginInstanceManager.destroy(); mPluginInstanceManager.destroy();
waitForIdleSync(mPluginInstanceManager.mPluginHandler); waitForIdleSync(mPluginInstanceManager.mPluginHandler);
waitForIdleSync(mPluginInstanceManager.mMainHandler); mFakeExecutor.runAllReady();
// Verify shutdown lifecycle // Verify shutdown lifecycle
verify(mMockListener).onPluginDisconnected(ArgumentCaptor.forClass(Plugin.class).capture()); verify(mMockListener).onPluginDisconnected(ArgumentCaptor.forClass(Plugin.class).capture());
@@ -165,7 +157,8 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
mPluginInstanceManager.loadAll(); mPluginInstanceManager.loadAll();
waitForIdleSync(mPluginInstanceManager.mPluginHandler); waitForIdleSync(mPluginInstanceManager.mPluginHandler);
waitForIdleSync(mPluginInstanceManager.mMainHandler); mFakeExecutor.runAllReady();
// Plugin shouldn't be connected because it is the wrong version. // Plugin shouldn't be connected because it is the wrong version.
verify(mMockListener, never()).onPluginConnected(any(), any()); verify(mMockListener, never()).onPluginConnected(any(), any());
@@ -179,7 +172,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
mPluginInstanceManager.onPackageChange("com.android.systemui"); mPluginInstanceManager.onPackageChange("com.android.systemui");
waitForIdleSync(mPluginInstanceManager.mPluginHandler); waitForIdleSync(mPluginInstanceManager.mPluginHandler);
waitForIdleSync(mPluginInstanceManager.mMainHandler); mFakeExecutor.runAllReady();
// Verify the old one was destroyed. // Verify the old one was destroyed.
verify(mMockListener).onPluginDisconnected(ArgumentCaptor.forClass(Plugin.class).capture()); verify(mMockListener).onPluginDisconnected(ArgumentCaptor.forClass(Plugin.class).capture());
@@ -195,14 +188,14 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
public void testNonDebuggable() throws Exception { public void testNonDebuggable() throws Exception {
// Create a version that thinks the build is not debuggable. // Create a version that thinks the build is not debuggable.
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction", mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo, mMockListener, true, mFakeExecutor, mHandlerThread.getLooper(),
mMockManager, false, new String[0], mInitializer); mMockVersionInfo, mMockManager, false, new String[0], mInitializer);
setupFakePmQuery(); setupFakePmQuery();
mPluginInstanceManager.loadAll(); mPluginInstanceManager.loadAll();
waitForIdleSync(mPluginInstanceManager.mPluginHandler); waitForIdleSync(mPluginInstanceManager.mPluginHandler);
waitForIdleSync(mPluginInstanceManager.mMainHandler);; mFakeExecutor.runAllReady();
// Non-debuggable build should receive no plugins. // Non-debuggable build should receive no plugins.
verify(mMockListener, never()).onPluginConnected(any(), any()); verify(mMockListener, never()).onPluginConnected(any(), any());
@@ -212,14 +205,15 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
public void testNonDebuggable_whitelist() throws Exception { public void testNonDebuggable_whitelist() throws Exception {
// Create a version that thinks the build is not debuggable. // Create a version that thinks the build is not debuggable.
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction", mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo, mMockListener, true, mFakeExecutor, mHandlerThread.getLooper(),
mMockManager, false, new String[] {WHITELISTED_PACKAGE}, mInitializer); mMockVersionInfo, mMockManager, false,
new String[] {WHITELISTED_PACKAGE}, mInitializer);
setupFakePmQuery(); setupFakePmQuery();
mPluginInstanceManager.loadAll(); mPluginInstanceManager.loadAll();
waitForIdleSync(mPluginInstanceManager.mPluginHandler); waitForIdleSync(mPluginInstanceManager.mPluginHandler);
waitForIdleSync(mPluginInstanceManager.mMainHandler); mFakeExecutor.runAllReady();
// Verify startup lifecycle // Verify startup lifecycle
verify(sMockPlugin).onCreate(ArgumentCaptor.forClass(Context.class).capture(), verify(sMockPlugin).onCreate(ArgumentCaptor.forClass(Context.class).capture(),
@@ -256,8 +250,9 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
@Test @Test
public void testDisableWhitelisted() throws Exception { public void testDisableWhitelisted() throws Exception {
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction", mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo, mMockListener, true, mFakeExecutor, mHandlerThread.getLooper(),
mMockManager, false, new String[] {WHITELISTED_PACKAGE}, mInitializer); mMockVersionInfo, mMockManager, false, new String[] {WHITELISTED_PACKAGE},
mInitializer);
createPlugin(); // Get into valid created state. createPlugin(); // Get into valid created state.
mPluginInstanceManager.disableAll(); mPluginInstanceManager.disableAll();
@@ -294,7 +289,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
mPluginInstanceManager.loadAll(); mPluginInstanceManager.loadAll();
waitForIdleSync(mPluginInstanceManager.mPluginHandler); waitForIdleSync(mPluginInstanceManager.mPluginHandler);
waitForIdleSync(mPluginInstanceManager.mMainHandler); mFakeExecutor.runAllReady();
} }
// Real context with no registering/unregistering of receivers. // Real context with no registering/unregistering of receivers.

View File

@@ -15,7 +15,6 @@ package com.android.systemui.shared.plugins;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@@ -37,7 +36,6 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.annotations.ProvidesInterface; import com.android.systemui.plugins.annotations.ProvidesInterface;
import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -90,16 +88,6 @@ public class PluginManagerTest extends SysuiTestCase {
mMockListener = mock(PluginListener.class); mMockListener = mock(PluginListener.class);
} }
@RunWithLooper(setAsMainLooper = true)
@Test
public void testOneShot() {
Plugin mockPlugin = mock(Plugin.class);
when(mMockPluginInstance.getPlugin()).thenReturn(new PluginInfo(null, null, mockPlugin,
null, null));
Plugin result = mPluginManager.getOneShotPlugin("myAction", TestPlugin.class);
assertSame(mockPlugin, result);
}
@Test @Test
public void testAddListener() { public void testAddListener() {
mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class); mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
@@ -129,7 +117,6 @@ public class PluginManagerTest extends SysuiTestCase {
applicationInfo.sourceDir = sourceDir; applicationInfo.sourceDir = sourceDir;
applicationInfo.packageName = WHITELISTED_PACKAGE; applicationInfo.packageName = WHITELISTED_PACKAGE;
mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class); mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
assertNull(mPluginManager.getOneShotPlugin(sourceDir, TestPlugin.class));
assertNull(mPluginManager.getClassLoader(applicationInfo)); assertNull(mPluginManager.getClassLoader(applicationInfo));
} }
@@ -206,8 +193,8 @@ public class PluginManagerTest extends SysuiTestCase {
} }
@ProvidesInterface(action = TestPlugin.ACTION, version = TestPlugin.VERSION) @ProvidesInterface(action = TestPlugin.ACTION, version = TestPlugin.VERSION)
public static interface TestPlugin extends Plugin { public interface TestPlugin extends Plugin {
public static final String ACTION = "testAction"; String ACTION = "testAction";
public static final int VERSION = 1; int VERSION = 1;
} }
} }

View File

@@ -65,14 +65,4 @@ public class FakePluginManager implements PluginManager {
public String[] getPrivilegedPlugins() { public String[] getPrivilegedPlugins() {
return new String[0]; return new String[0];
} }
@Override
public <T extends Plugin> T getOneShotPlugin(Class<T> cls) {
return null;
}
@Override
public <T extends Plugin> T getOneShotPlugin(String action, Class<?> cls) {
return null;
}
} }