Merge "DO NOT MERGE Separate intent handling code into separate activity" into pi-car-dev
diff --git a/src/com/android/car/settings/applications/specialaccess/AppEntryListManager.java b/src/com/android/car/settings/applications/specialaccess/AppEntryListManager.java
new file mode 100644
index 0000000..1039a74
--- /dev/null
+++ b/src/com/android/car/settings/applications/specialaccess/AppEntryListManager.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2019 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.car.settings.applications.specialaccess;
+
+import android.app.Application;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+import androidx.annotation.Nullable;
+
+import com.android.settingslib.applications.ApplicationsState;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Manages a list of {@link ApplicationsState.AppEntry} instances by syncing in the background and
+ * providing updates via a {@link Callback}. Clients may provide an {@link ExtraInfoBridge} to
+ * populate the {@link ApplicationsState.AppEntry#extraInfo} field with use case sepecific data.
+ * Clients may also provide an {@link ApplicationsState.AppFilter} via an {@link AppFilterProvider}
+ * to determine which entries will appear in the list updates.
+ *
+ * <p>Clients should call {@link #init(ExtraInfoBridge, AppFilterProvider, Callback)} to specify
+ * behavior and then {@link #start()} to begin loading. {@link #stop()} will cancel loading, and
+ * {@link #destroy()} will clean up resources when this class will no longer be used.
+ */
+public class AppEntryListManager {
+
+ /** Callback for receiving events from {@link AppEntryListManager}. */
+ public interface Callback {
+ /**
+ * Called when the list of {@link ApplicationsState.AppEntry} instances or the {@link
+ * ApplicationsState.AppEntry#extraInfo} fields have changed.
+ */
+ void onAppEntryListChanged(List<ApplicationsState.AppEntry> entries);
+ }
+
+ /**
+ * Provides an {@link ApplicationsState.AppFilter} to tailor the entries in the list updates.
+ */
+ public interface AppFilterProvider {
+ /**
+ * Returns the filter that should be used to trim the entries list before callback delivery.
+ */
+ ApplicationsState.AppFilter getAppFilter();
+ }
+
+ /** Bridges extra information to {@link ApplicationsState.AppEntry#extraInfo}. */
+ public interface ExtraInfoBridge {
+ /**
+ * Populates the {@link ApplicationsState.AppEntry#extraInfo} field on the {@code enrties}
+ * with the relevant data for the implementation.
+ */
+ void loadExtraInfo(List<ApplicationsState.AppEntry> entries);
+ }
+
+ private final ApplicationsState.Callbacks mSessionCallbacks =
+ new ApplicationsState.Callbacks() {
+ @Override
+ public void onRunningStateChanged(boolean running) {
+ // No op.
+ }
+
+ @Override
+ public void onPackageListChanged() {
+ forceUpdate();
+ }
+
+ @Override
+ public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {
+ if (mCallback != null) {
+ mCallback.onAppEntryListChanged(apps);
+ }
+ }
+
+ @Override
+ public void onPackageIconChanged() {
+ // No op.
+ }
+
+ @Override
+ public void onPackageSizeChanged(String packageName) {
+ // No op.
+ }
+
+ @Override
+ public void onAllSizesComputed() {
+ // No op.
+ }
+
+ @Override
+ public void onLauncherInfoChanged() {
+ // No op.
+ }
+
+ @Override
+ public void onLoadEntriesCompleted() {
+ mHasReceivedLoadEntries = true;
+ forceUpdate();
+ }
+ };
+
+ private final ApplicationsState mApplicationsState;
+ private final BackgroundHandler mBackgroundHandler;
+ private final MainHandler mMainHandler;
+
+ private ExtraInfoBridge mExtraInfoBridge;
+ private AppFilterProvider mFilterProvider;
+ private Callback mCallback;
+ private ApplicationsState.Session mSession;
+
+ private boolean mHasReceivedLoadEntries;
+ private boolean mHasReceivedExtraInfo;
+
+ public AppEntryListManager(Context context) {
+ mApplicationsState = ApplicationsState.getInstance(
+ (Application) context.getApplicationContext());
+ // Run on the same background thread as the ApplicationsState to make sure updates don't
+ // conflict.
+ mBackgroundHandler = new BackgroundHandler(new WeakReference<>(this),
+ mApplicationsState.getBackgroundLooper());
+ mMainHandler = new MainHandler(new WeakReference<>(this));
+ }
+
+ /**
+ * Specifies the behavior of this manager.
+ *
+ * @param extraInfoBridge an optional bridge to load information into the entries.
+ * @param filterProvider provides a filter to tailor the contents of the list updates.
+ * @param callback callback to which updated lists are delivered.
+ */
+ public void init(@Nullable ExtraInfoBridge extraInfoBridge,
+ @Nullable AppFilterProvider filterProvider,
+ Callback callback) {
+ if (mSession != null) {
+ destroy();
+ }
+ mExtraInfoBridge = extraInfoBridge;
+ mFilterProvider = filterProvider;
+ mCallback = callback;
+ mSession = mApplicationsState.newSession(mSessionCallbacks);
+ }
+
+ /**
+ * Starts loading the information in the background. When loading is finished, the {@link
+ * Callback} will be notified on the main thread.
+ */
+ public void start() {
+ mSession.onResume();
+ }
+
+ /**
+ * Stops any pending loading.
+ */
+ public void stop() {
+ mSession.onPause();
+ clearHandlers();
+ }
+
+ /**
+ * Cleans up internal state when this will no longer be used.
+ */
+ public void destroy() {
+ mSession.onDestroy();
+ clearHandlers();
+ mExtraInfoBridge = null;
+ mFilterProvider = null;
+ mCallback = null;
+ }
+
+ /**
+ * Schedules updates for all {@link ApplicationsState.AppEntry} instances. When loading is
+ * finished, the {@link Callback} will be notified on the main thread.
+ */
+ public void forceUpdate() {
+ mBackgroundHandler.sendEmptyMessage(BackgroundHandler.MSG_LOAD_ALL);
+ }
+
+ /**
+ * Schedules an update for the given {@code entry}. When loading is finished, the {@link
+ * Callback} will be notified on the main thread.
+ */
+ public void forceUpdate(ApplicationsState.AppEntry entry) {
+ mBackgroundHandler.obtainMessage(BackgroundHandler.MSG_LOAD_PKG,
+ entry).sendToTarget();
+ }
+
+ private void rebuild() {
+ if (!mHasReceivedLoadEntries || !mHasReceivedExtraInfo) {
+ // Don't rebuild the list until all the app entries are loaded.
+ return;
+ }
+ mSession.rebuild((mFilterProvider != null) ? mFilterProvider.getAppFilter()
+ : ApplicationsState.FILTER_EVERYTHING,
+ ApplicationsState.ALPHA_COMPARATOR, /* foreground= */ false);
+ }
+
+ private void clearHandlers() {
+ mBackgroundHandler.removeMessages(BackgroundHandler.MSG_LOAD_ALL);
+ mBackgroundHandler.removeMessages(BackgroundHandler.MSG_LOAD_PKG);
+ mMainHandler.removeMessages(MainHandler.MSG_INFO_UPDATED);
+ }
+
+ private static class BackgroundHandler extends Handler {
+ private static final int MSG_LOAD_ALL = 1;
+ private static final int MSG_LOAD_PKG = 2;
+
+ private final WeakReference<AppEntryListManager> mOuter;
+
+ BackgroundHandler(WeakReference<AppEntryListManager> outer, Looper looper) {
+ super(looper);
+ mOuter = outer;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ AppEntryListManager outer = mOuter.get();
+ if (outer == null) {
+ return;
+ }
+ switch (msg.what) {
+ case MSG_LOAD_ALL:
+ if (outer.mExtraInfoBridge != null) {
+ outer.mExtraInfoBridge.loadExtraInfo(outer.mSession.getAllApps());
+ }
+ outer.mMainHandler.sendEmptyMessage(MainHandler.MSG_INFO_UPDATED);
+ break;
+ case MSG_LOAD_PKG:
+ ApplicationsState.AppEntry entry = (ApplicationsState.AppEntry) msg.obj;
+ if (outer.mExtraInfoBridge != null) {
+ outer.mExtraInfoBridge.loadExtraInfo(Collections.singletonList(entry));
+ }
+ outer.mMainHandler.sendEmptyMessage(MainHandler.MSG_INFO_UPDATED);
+ break;
+ }
+ }
+ }
+
+ private static class MainHandler extends Handler {
+ private static final int MSG_INFO_UPDATED = 1;
+
+ private final WeakReference<AppEntryListManager> mOuter;
+
+ MainHandler(WeakReference<AppEntryListManager> outer) {
+ mOuter = outer;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ AppEntryListManager outer = mOuter.get();
+ if (outer == null) {
+ return;
+ }
+ switch (msg.what) {
+ case MSG_INFO_UPDATED:
+ outer.mHasReceivedExtraInfo = true;
+ outer.rebuild();
+ break;
+ }
+ }
+ }
+}
diff --git a/src/com/android/car/settings/applications/specialaccess/AppOpsPreferenceController.java b/src/com/android/car/settings/applications/specialaccess/AppOpsPreferenceController.java
index a3fea69..2ce7aac 100644
--- a/src/com/android/car/settings/applications/specialaccess/AppOpsPreferenceController.java
+++ b/src/com/android/car/settings/applications/specialaccess/AppOpsPreferenceController.java
@@ -24,6 +24,7 @@
import android.content.pm.PackageManager;
import androidx.annotation.CallSuper;
+import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.SwitchPreference;
@@ -37,7 +38,7 @@
import com.android.settingslib.applications.ApplicationsState.AppFilter;
import com.android.settingslib.applications.ApplicationsState.CompoundFilter;
-import java.util.ArrayList;
+import java.util.List;
/**
* Displays a list of toggles for applications requesting permission to perform the operation with
@@ -62,59 +63,6 @@
private final AppOpsManager mAppOpsManager;
private final ApplicationsState mApplicationsState;
- private final ApplicationsState.Callbacks mCallbacks =
- new ApplicationsState.Callbacks() {
- @Override
- public void onRunningStateChanged(boolean running) {
- // TODO: show loading UI.
- }
-
- @Override
- public void onPackageListChanged() {
- rebuild();
- }
-
- @Override
- public void onRebuildComplete(ArrayList<AppEntry> entries) {
- mEntries = entries;
- refreshUi();
- }
-
- @Override
- public void onPackageIconChanged() {
- // No op.
- }
-
- @Override
- public void onPackageSizeChanged(String packageName) {
- // No op.
- }
-
- @Override
- public void onAllSizesComputed() {
- // No op.
- }
-
- @Override
- public void onLauncherInfoChanged() {
- rebuild();
- }
-
- @Override
- public void onLoadEntriesCompleted() {
- mHasReceivedLoadEntries = true;
- rebuild();
- }
- };
-
- private final AppStateBaseBridge.Callback mBridgeCallback = new AppStateBaseBridge.Callback() {
- @Override
- public void onExtraInfoUpdated() {
- mHasReceivedBridgeCallback = true;
- rebuild();
- }
- };
-
private final Preference.OnPreferenceChangeListener mOnPreferenceChangeListener =
new Preference.OnPreferenceChangeListener() {
@Override
@@ -128,24 +76,28 @@
entry.info.packageName,
allowOp ? AppOpsManager.MODE_ALLOWED : mNegativeOpMode);
// Update the extra info of this entry so that it reflects the new mode.
- mExtraInfoBridge.forceUpdate(entry);
+ mAppEntryListManager.forceUpdate(entry);
return true;
}
return false;
}
};
+ private final AppEntryListManager.Callback mCallback = new AppEntryListManager.Callback() {
+ @Override
+ public void onAppEntryListChanged(List<AppEntry> entries) {
+ mEntries = entries;
+ refreshUi();
+ }
+ };
+
private int mAppOpsOpCode = AppOpsManager.OP_NONE;
private String mPermission;
private int mNegativeOpMode = -1;
- private ApplicationsState.Session mSession;
- private AppStateAppOpsBridge mExtraInfoBridge;
-
- private ArrayList<AppEntry> mEntries;
-
- private boolean mHasReceivedLoadEntries;
- private boolean mHasReceivedBridgeCallback;
+ @VisibleForTesting
+ AppEntryListManager mAppEntryListManager;
+ private List<AppEntry> mEntries;
private boolean mShowSystem;
@@ -155,6 +107,7 @@
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mApplicationsState = ApplicationsState.getInstance(
(Application) context.getApplicationContext());
+ mAppEntryListManager = new AppEntryListManager(context);
}
@Override
@@ -185,7 +138,7 @@
public void setShowSystem(boolean showSystem) {
if (mShowSystem != showSystem) {
mShowSystem = showSystem;
- rebuild();
+ mAppEntryListManager.forceUpdate();
}
}
@@ -204,27 +157,24 @@
@Override
protected void onCreateInternal() {
- mSession = mApplicationsState.newSession(mCallbacks);
- mExtraInfoBridge = new AppStateAppOpsBridge(getContext(), mApplicationsState, mAppOpsOpCode,
- mPermission, mBridgeCallback);
+ AppStateAppOpsBridge extraInfoBridge = new AppStateAppOpsBridge(getContext(), mAppOpsOpCode,
+ mPermission);
+ mAppEntryListManager.init(extraInfoBridge, this::getAppFilter, mCallback);
}
@Override
protected void onStartInternal() {
- mSession.onResume();
- mExtraInfoBridge.start();
+ mAppEntryListManager.start();
}
@Override
protected void onStopInternal() {
- mSession.onPause();
- mExtraInfoBridge.stop();
+ mAppEntryListManager.stop();
}
@Override
protected void onDestroyInternal() {
- mSession.onDestroy();
- mExtraInfoBridge.destroy();
+ mAppEntryListManager.destroy();
}
@Override
@@ -253,15 +203,6 @@
return filterObj;
}
- private void rebuild() {
- if (!mHasReceivedLoadEntries || !mHasReceivedBridgeCallback) {
- // Don't rebuild the list until all the app entries are loaded.
- return;
- }
- mSession.rebuild(getAppFilter(), ApplicationsState.ALPHA_COMPARATOR, /* foreground= */
- false);
- }
-
private static class AppOpPreference extends SwitchPreference {
private final AppEntry mEntry;
diff --git a/src/com/android/car/settings/applications/specialaccess/AppStateAppOpsBridge.java b/src/com/android/car/settings/applications/specialaccess/AppStateAppOpsBridge.java
index e278a3a..4a3d0a1 100644
--- a/src/com/android/car/settings/applications/specialaccess/AppStateAppOpsBridge.java
+++ b/src/com/android/car/settings/applications/specialaccess/AppStateAppOpsBridge.java
@@ -32,7 +32,6 @@
import com.android.car.settings.common.Logger;
import com.android.internal.util.ArrayUtils;
-import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import java.util.List;
@@ -42,7 +41,7 @@
* Bridges {@link AppOpsManager} app operation permission information into {@link
* AppEntry#extraInfo} as {@link PermissionState} objects.
*/
-public class AppStateAppOpsBridge extends AppStateBaseBridge {
+public class AppStateAppOpsBridge implements AppEntryListManager.ExtraInfoBridge {
private static final Logger LOG = new Logger(AppStateAppOpsBridge.class);
@@ -59,18 +58,14 @@
* @param appOpsOpCode the {@link AppOpsManager} op code constant to fetch information for.
* @param permission the {@link android.Manifest.permission} required to perform the
* operation.
- * @param callback a {@link Callback} which will be notified when the information is
- * finished loading.
*/
- public AppStateAppOpsBridge(Context context, ApplicationsState appState, int appOpsOpCode,
- String permission, Callback callback) {
- this(context, appState, appOpsOpCode, permission, callback, AppGlobals.getPackageManager());
+ public AppStateAppOpsBridge(Context context, int appOpsOpCode, String permission) {
+ this(context, appOpsOpCode, permission, AppGlobals.getPackageManager());
}
@VisibleForTesting
- AppStateAppOpsBridge(Context context, ApplicationsState appState, int appOpsOpCode,
- String permission, Callback callback, IPackageManager packageManager) {
- super(appState, callback);
+ AppStateAppOpsBridge(Context context, int appOpsOpCode, String permission,
+ IPackageManager packageManager) {
mContext = context;
mIPackageManager = packageManager;
mProfiles = UserManager.get(context).getUserProfiles();
@@ -80,7 +75,7 @@
}
@Override
- protected void loadExtraInfo(List<AppEntry> entries) {
+ public void loadExtraInfo(List<AppEntry> entries) {
SparseArray<Map<String, PermissionState>> packageToStatesMapByProfileId =
getPackageToStateMapsByProfileId();
loadAppOpModes(packageToStatesMapByProfileId);
diff --git a/src/com/android/car/settings/applications/specialaccess/AppStateBaseBridge.java b/src/com/android/car/settings/applications/specialaccess/AppStateBaseBridge.java
deleted file mode 100644
index 507516c..0000000
--- a/src/com/android/car/settings/applications/specialaccess/AppStateBaseBridge.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright 2019 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.car.settings.applications.specialaccess;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-
-import com.android.settingslib.applications.ApplicationsState;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Common base class for bridging information to {@link ApplicationsState.AppEntry#extraInfo}.
- * Subclasses should implement {@link #loadExtraInfo(List)} and populate the fields in the given
- * {@link ApplicationsState.AppEntry} instances.
- */
-public abstract class AppStateBaseBridge {
-
- /** Callback for receiving events from the bridge. */
- public interface Callback {
- /**
- * Called when the bridge has finished updating all
- * {@link ApplicationsState.AppEntry#extraInfo} in {@link ApplicationsState}.
- */
- void onExtraInfoUpdated();
- }
-
- private final ApplicationsState.Session mSession;
- private final Callback mCallback;
- private final BackgroundHandler mBackgroundHandler;
- private final MainHandler mMainHandler;
-
- private final ApplicationsState.Callbacks mSessionCallbacks =
- new ApplicationsState.Callbacks() {
- @Override
- public void onRunningStateChanged(boolean running) {
- // No op.
- }
-
- @Override
- public void onPackageListChanged() {
- mBackgroundHandler.sendEmptyMessage(BackgroundHandler.MSG_LOAD_ALL);
- }
-
- @Override
- public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {
- // No op.
- }
-
- @Override
- public void onPackageIconChanged() {
- // No op.
- }
-
- @Override
- public void onPackageSizeChanged(String packageName) {
- // No op.
- }
-
- @Override
- public void onAllSizesComputed() {
- // No op.
- }
-
- @Override
- public void onLauncherInfoChanged() {
- // No op.
- }
-
- @Override
- public void onLoadEntriesCompleted() {
- mBackgroundHandler.sendEmptyMessage(BackgroundHandler.MSG_LOAD_ALL);
- }
- };
-
- private boolean mIsStarted;
-
- public AppStateBaseBridge(ApplicationsState applicationsState, Callback callback) {
- mSession = applicationsState.newSession(mSessionCallbacks);
- mCallback = callback;
- // Run on the same background thread as the ApplicationsState to make sure updates don't
- // conflict.
- mBackgroundHandler = new BackgroundHandler(new WeakReference<>(this),
- applicationsState.getBackgroundLooper());
- mMainHandler = new MainHandler(new WeakReference<>(this));
- }
-
- /**
- * Starts loading the information in the background. When loading is finished, the {@link
- * Callback} will be notified on the main thread.
- */
- public void start() {
- mIsStarted = true;
- mBackgroundHandler.sendEmptyMessage(BackgroundHandler.MSG_LOAD_ALL);
- mSession.onResume();
- }
-
- /**
- * Stops any pending loading. In progress loading may still complete, but no {@link Callback}
- * notifications will be delivered.
- */
- public void stop() {
- mIsStarted = false;
- mBackgroundHandler.removeMessages(BackgroundHandler.MSG_LOAD_ALL);
- mSession.onPause();
- }
-
- /**
- * Cleans up internal state when this bridge will no longer be used.
- */
- public void destroy() {
- mSession.onDestroy();
- }
-
- /**
- * Updates the {@link ApplicationsState.AppEntry#extraInfo} of the given {@code entry}. When
- * loading is finished, the {@link Callback} will be notified on the main thread.
- */
- public void forceUpdate(ApplicationsState.AppEntry entry) {
- mBackgroundHandler.obtainMessage(BackgroundHandler.MSG_FORCE_LOAD_PKG,
- entry).sendToTarget();
- }
-
- /**
- * Populates the {@link ApplicationsState.AppEntry#extraInfo} field on the {@code enrties} with
- * the relevant data for the subclass.
- */
- protected abstract void loadExtraInfo(List<ApplicationsState.AppEntry> entries);
-
- private static class BackgroundHandler extends Handler {
- private static final int MSG_LOAD_ALL = 1;
- private static final int MSG_FORCE_LOAD_PKG = 2;
-
- private final WeakReference<AppStateBaseBridge> mOuter;
-
- BackgroundHandler(WeakReference<AppStateBaseBridge> outer, Looper looper) {
- super(looper);
- mOuter = outer;
- }
-
- @Override
- public void handleMessage(Message msg) {
- AppStateBaseBridge outer = mOuter.get();
- if (outer == null) {
- return;
- }
- switch (msg.what) {
- case MSG_LOAD_ALL:
- outer.loadExtraInfo(outer.mSession.getAllApps());
- outer.mMainHandler.sendEmptyMessage(MainHandler.MSG_INFO_UPDATED);
- break;
- case MSG_FORCE_LOAD_PKG:
- ApplicationsState.AppEntry entry = (ApplicationsState.AppEntry) msg.obj;
- outer.loadExtraInfo(Collections.singletonList(entry));
- outer.mMainHandler.sendEmptyMessage(MainHandler.MSG_INFO_UPDATED);
- break;
- }
- }
- }
-
- private static class MainHandler extends Handler {
- private static final int MSG_INFO_UPDATED = 1;
-
- private final WeakReference<AppStateBaseBridge> mOuter;
-
- MainHandler(WeakReference<AppStateBaseBridge> outer) {
- mOuter = outer;
- }
-
- @Override
- public void handleMessage(Message msg) {
- AppStateBaseBridge outer = mOuter.get();
- if (outer == null) {
- return;
- }
- switch (msg.what) {
- case MSG_INFO_UPDATED:
- if (outer.mIsStarted) {
- outer.mCallback.onExtraInfoUpdated();
- }
- break;
- }
- }
- }
-}
diff --git a/tests/robotests/src/com/android/car/settings/applications/specialaccess/AppEntryListManagerTest.java b/tests/robotests/src/com/android/car/settings/applications/specialaccess/AppEntryListManagerTest.java
new file mode 100644
index 0000000..96143f9
--- /dev/null
+++ b/tests/robotests/src/com/android/car/settings/applications/specialaccess/AppEntryListManagerTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2019 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.car.settings.applications.specialaccess;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Looper;
+
+import com.android.car.settings.CarSettingsRobolectricTestRunner;
+import com.android.car.settings.testutils.ShadowApplicationsState;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Unit test for {@link AppEntryListManager}. */
+@RunWith(CarSettingsRobolectricTestRunner.class)
+@Config(shadows = {ShadowApplicationsState.class})
+public class AppEntryListManagerTest {
+
+ @Mock
+ private ApplicationsState mApplicationsState;
+ @Mock
+ private ApplicationsState.Session mSession;
+ @Mock
+ private AppEntryListManager.ExtraInfoBridge mExtraInfoBridge;
+ @Mock
+ private AppEntryListManager.AppFilterProvider mFilterProvider;
+ @Mock
+ private AppEntryListManager.Callback mCallback;
+ @Captor
+ private ArgumentCaptor<ApplicationsState.Callbacks> mSessionCallbacksCaptor;
+ @Captor
+ private ArgumentCaptor<List<AppEntry>> mEntriesCaptor;
+
+ private AppEntryListManager mAppEntryListManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ ShadowApplicationsState.setInstance(mApplicationsState);
+ when(mApplicationsState.newSession(mSessionCallbacksCaptor.capture())).thenReturn(mSession);
+ when(mApplicationsState.getBackgroundLooper()).thenReturn(Looper.getMainLooper());
+
+ mAppEntryListManager = new AppEntryListManager(RuntimeEnvironment.application);
+ mAppEntryListManager.init(mExtraInfoBridge, mFilterProvider, mCallback);
+ }
+
+ @After
+ public void tearDown() {
+ ShadowApplicationsState.reset();
+ }
+
+ @Test
+ public void start_resumesSession() {
+ mAppEntryListManager.start();
+
+ verify(mSession).onResume();
+ }
+
+ @Test
+ public void onPackageListChanged_loadsExtraInfo() {
+ mSessionCallbacksCaptor.getValue().onPackageListChanged();
+
+ verify(mExtraInfoBridge).loadExtraInfo(any());
+ }
+
+ @Test
+ public void onLoadEntriesComplete_loadsExtraInfo() {
+ mSessionCallbacksCaptor.getValue().onLoadEntriesCompleted();
+
+ verify(mExtraInfoBridge).loadExtraInfo(any());
+ }
+
+ @Test
+ public void stop_pausesSession() {
+ mAppEntryListManager.stop();
+
+ verify(mSession).onPause();
+ }
+
+ @Test
+ public void destroy_destroysSession() {
+ mAppEntryListManager.destroy();
+
+ verify(mSession).onDestroy();
+ }
+
+ @Test
+ public void forceUpdate_loadsExtraInfo() {
+ ArrayList<AppEntry> entries = new ArrayList<>();
+ entries.add(mock(AppEntry.class));
+ when(mSession.getAllApps()).thenReturn(entries);
+
+ mAppEntryListManager.forceUpdate();
+
+ verify(mExtraInfoBridge).loadExtraInfo(entries);
+ }
+
+ @Test
+ public void forceUpdate_forEntry_loadsExtraInfo() {
+ AppEntry entry = mock(AppEntry.class);
+
+ mAppEntryListManager.forceUpdate(entry);
+
+ verify(mExtraInfoBridge).loadExtraInfo(mEntriesCaptor.capture());
+ assertThat(mEntriesCaptor.getValue()).containsExactly(entry);
+ }
+
+ @Test
+ public void loadingFinished_rebuildsSession() {
+ ApplicationsState.AppFilter appFilter = mock(ApplicationsState.AppFilter.class);
+ when(mFilterProvider.getAppFilter()).thenReturn(appFilter);
+
+ mSessionCallbacksCaptor.getValue().onLoadEntriesCompleted();
+
+ verify(mSession).rebuild(eq(appFilter),
+ eq(ApplicationsState.ALPHA_COMPARATOR), /* foreground= */ eq(false));
+ }
+
+ @Test
+ public void onRebuildComplete_callsCallback() {
+ ArrayList<AppEntry> entries = new ArrayList<>();
+ entries.add(mock(AppEntry.class));
+
+ mSessionCallbacksCaptor.getValue().onRebuildComplete(entries);
+
+ verify(mCallback).onAppEntryListChanged(entries);
+ }
+}
diff --git a/tests/robotests/src/com/android/car/settings/applications/specialaccess/AppOpsPreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/applications/specialaccess/AppOpsPreferenceControllerTest.java
index 497bd95..b8e70f3 100644
--- a/tests/robotests/src/com/android/car/settings/applications/specialaccess/AppOpsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/car/settings/applications/specialaccess/AppOpsPreferenceControllerTest.java
@@ -19,9 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
@@ -30,13 +28,8 @@
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
import android.os.Looper;
import android.os.RemoteException;
-import android.os.UserHandle;
import androidx.lifecycle.Lifecycle;
import androidx.preference.PreferenceGroup;
@@ -45,7 +38,6 @@
import com.android.car.settings.CarSettingsRobolectricTestRunner;
import com.android.car.settings.common.LogicalPreferenceGroup;
import com.android.car.settings.common.PreferenceControllerTestHelper;
-import com.android.car.settings.testutils.ShadowActivityThread;
import com.android.car.settings.testutils.ShadowAppOpsManager;
import com.android.car.settings.testutils.ShadowApplicationsState;
import com.android.settingslib.applications.ApplicationsState;
@@ -55,7 +47,6 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.AdditionalMatchers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
@@ -64,13 +55,13 @@
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
-import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
/** Unit test for {@link AppOpsPreferenceController}. */
@RunWith(CarSettingsRobolectricTestRunner.class)
-@Config(shadows = {ShadowAppOpsManager.class, ShadowApplicationsState.class,
- ShadowActivityThread.class})
+@Config(shadows = {ShadowAppOpsManager.class, ShadowApplicationsState.class})
public class AppOpsPreferenceControllerTest {
private static final int APP_OP_CODE = AppOpsManager.OP_WRITE_SETTINGS;
@@ -78,17 +69,11 @@
private static final int NEGATIVE_MODE = AppOpsManager.MODE_ERRORED;
@Mock
- private IPackageManager mIPackageManager;
- @Mock
- private ParceledListSlice<PackageInfo> mParceledPackages;
+ private AppEntryListManager mAppEntryListManager;
@Mock
private ApplicationsState mApplicationsState;
- @Mock
- private ApplicationsState.Session mSession;
- @Mock
- private ApplicationsState.Session mBridgeSession;
@Captor
- private ArgumentCaptor<ApplicationsState.Callbacks> mCallbackCaptor;
+ private ArgumentCaptor<AppEntryListManager.Callback> mCallbackCaptor;
private Context mContext;
private PreferenceGroup mPreferenceGroup;
@@ -98,17 +83,7 @@
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
- ShadowActivityThread.setPackageManager(mIPackageManager);
- when(mIPackageManager.getPackagesHoldingPermissions(
- AdditionalMatchers.aryEq(new String[]{PERMISSION}),
- eq(PackageManager.GET_PERMISSIONS),
- eq(UserHandle.myUserId())))
- .thenReturn(mParceledPackages);
- when(mParceledPackages.getList()).thenReturn(Collections.emptyList());
ShadowApplicationsState.setInstance(mApplicationsState);
- when(mApplicationsState.newSession(mCallbackCaptor.capture()))
- .thenReturn(mSession)
- .thenReturn(mBridgeSession);
when(mApplicationsState.getBackgroundLooper()).thenReturn(Looper.getMainLooper());
mContext = RuntimeEnvironment.application;
@@ -117,14 +92,16 @@
AppOpsPreferenceController.class);
mController = mControllerHelper.getController();
mController.init(APP_OP_CODE, PERMISSION, NEGATIVE_MODE);
+ mController.mAppEntryListManager = mAppEntryListManager;
mControllerHelper.setPreference(mPreferenceGroup);
mControllerHelper.markState(Lifecycle.State.CREATED);
+ verify(mAppEntryListManager).init(any(AppStateAppOpsBridge.class), any(),
+ mCallbackCaptor.capture());
}
@After
public void tearDown() {
ShadowApplicationsState.reset();
- ShadowActivityThread.reset();
}
@Test
@@ -164,54 +141,35 @@
}
@Test
- public void onStart_resumesSessions() {
+ public void onStart_startsListManager() {
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
- verify(mSession).onResume();
- verify(mBridgeSession).onResume();
+ verify(mAppEntryListManager).start();
}
@Test
- public void onStop_pausesSessions() {
+ public void onStop_stopsListManager() {
mControllerHelper.markState(Lifecycle.State.STARTED);
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_STOP);
- verify(mSession).onPause();
- verify(mBridgeSession).onPause();
+ verify(mAppEntryListManager).stop();
}
@Test
- public void onDestroy_destroysSessions() {
+ public void onDestroy_destroysListManager() {
mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_DESTROY);
- verify(mSession).onDestroy();
- verify(mBridgeSession).onDestroy();
+ verify(mAppEntryListManager).destroy();
}
@Test
- public void onLoadEntriesCompleted_extraInfoUpdated_rebuildsEntries() {
+ public void onAppEntryListChanged_addsPreferencesForEntries() {
mControllerHelper.markState(Lifecycle.State.STARTED);
- ApplicationsState.Callbacks callbacks = mCallbackCaptor.getAllValues().get(0);
-
- // Extra info updated callback happens synchronously onStart since we are using the main
- // looper for testing.
- callbacks.onLoadEntriesCompleted();
-
- verify(mSession).rebuild(any(), eq(ApplicationsState.ALPHA_COMPARATOR), /* foreground= */
- eq(false));
- }
-
- @Test
- public void onRebuildComplete_addsPreferencesForEntries() {
- mControllerHelper.markState(Lifecycle.State.STARTED);
- ApplicationsState.Callbacks callbacks = mCallbackCaptor.getAllValues().get(0);
- ArrayList<AppEntry> entries = new ArrayList<>();
- entries.add(createAppEntry("test.package", /* uid= */ 1, /* isOpPermissible= */ true));
- entries.add(
+ List<AppEntry> entries = Arrays.asList(
+ createAppEntry("test.package", /* uid= */ 1, /* isOpPermissible= */ true),
createAppEntry("another.test.package", /* uid= */ 2, /* isOpPermissible= */ false));
- callbacks.onLoadEntriesCompleted();
- callbacks.onRebuildComplete(entries);
+ mCallbackCaptor.getValue().onAppEntryListChanged(entries);
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2);
assertThat(((TwoStatePreference) mPreferenceGroup.getPreference(0)).isChecked()).isTrue();
@@ -221,13 +179,11 @@
@Test
public void onPreferenceChange_checkedState_setsAppOpModeAllowed() {
mControllerHelper.markState(Lifecycle.State.STARTED);
- ApplicationsState.Callbacks callbacks = mCallbackCaptor.getAllValues().get(0);
- ArrayList<AppEntry> entries = new ArrayList<>();
String packageName = "test.package";
int uid = 1;
- entries.add(createAppEntry("test.package", uid, /* isOpPermissible= */ false));
- callbacks.onLoadEntriesCompleted();
- callbacks.onRebuildComplete(entries);
+ List<AppEntry> entries = Collections.singletonList(
+ createAppEntry(packageName, uid, /* isOpPermissible= */ false));
+ mCallbackCaptor.getValue().onAppEntryListChanged(entries);
TwoStatePreference appPref = (TwoStatePreference) mPreferenceGroup.getPreference(0);
appPref.performClick();
@@ -239,13 +195,11 @@
@Test
public void onPreferenceChange_uncheckedState_setsNegativeAppOpMode() {
mControllerHelper.markState(Lifecycle.State.STARTED);
- ApplicationsState.Callbacks callbacks = mCallbackCaptor.getAllValues().get(0);
- ArrayList<AppEntry> entries = new ArrayList<>();
String packageName = "test.package";
int uid = 1;
- entries.add(createAppEntry("test.package", uid, /* isOpPermissible= */ true));
- callbacks.onLoadEntriesCompleted();
- callbacks.onRebuildComplete(entries);
+ List<AppEntry> entries = Collections.singletonList(
+ createAppEntry(packageName, uid, /* isOpPermissible= */ true));
+ mCallbackCaptor.getValue().onAppEntryListChanged(entries);
TwoStatePreference appPref = (TwoStatePreference) mPreferenceGroup.getPreference(0);
appPref.performClick();
@@ -255,54 +209,35 @@
}
@Test
- public void onPreferenceChange_rebuildsEntries() {
+ public void onPreferenceChange_updatesEntry() {
mControllerHelper.markState(Lifecycle.State.STARTED);
- ApplicationsState.Callbacks callbacks = mCallbackCaptor.getAllValues().get(0);
- ArrayList<AppEntry> entries = new ArrayList<>();
- String packageName = "test.package";
- int uid = 1;
- entries.add(createAppEntry("test.package", uid, /* isOpPermissible= */ false));
- callbacks.onLoadEntriesCompleted();
- callbacks.onRebuildComplete(entries);
+ List<AppEntry> entries = Collections.singletonList(
+ createAppEntry("test.package", /* uid= */ 1, /* isOpPermissible= */ false));
+ mCallbackCaptor.getValue().onAppEntryListChanged(entries);
TwoStatePreference appPref = (TwoStatePreference) mPreferenceGroup.getPreference(0);
appPref.performClick();
- // 2 times: onLoadEntriesCompleted, onPreferenceChange
- verify(mSession, times(2)).rebuild(any(),
- eq(ApplicationsState.ALPHA_COMPARATOR), /* foreground= */
- eq(false));
+ verify(mAppEntryListManager).forceUpdate(entries.get(0));
}
@Test
- public void showSystem_rebuildsEntries() {
+ public void showSystem_updatesEntries() {
mControllerHelper.markState(Lifecycle.State.STARTED);
- ApplicationsState.Callbacks callbacks = mCallbackCaptor.getAllValues().get(0);
- callbacks.onLoadEntriesCompleted();
mController.setShowSystem(true);
- // 2 times: onLoadEntriesCompleted, setShowSystem
- verify(mSession, times(2)).rebuild(any(),
- eq(ApplicationsState.ALPHA_COMPARATOR), /* foreground= */
- eq(false));
+ verify(mAppEntryListManager).forceUpdate();
}
@Test
- public void rebuildFilter_showingSystemApps_keepsSystemEntries() {
+ public void appFilter_showingSystemApps_keepsSystemEntries() {
mControllerHelper.markState(Lifecycle.State.STARTED);
- ApplicationsState.Callbacks callbacks = mCallbackCaptor.getAllValues().get(0);
- callbacks.onLoadEntriesCompleted();
mController.setShowSystem(true);
- ArgumentCaptor<ApplicationsState.AppFilter> filterCaptor = ArgumentCaptor.forClass(
- ApplicationsState.AppFilter.class);
- // 2 times: onLoadEntriesCompleted, setShowSystem
- verify(mSession, times(2)).rebuild(filterCaptor.capture(),
- eq(ApplicationsState.ALPHA_COMPARATOR), /* foreground= */
- eq(false));
-
- // Get the filter from setShowSystem.
- ApplicationsState.AppFilter filter = filterCaptor.getAllValues().get(1);
+ ArgumentCaptor<AppEntryListManager.AppFilterProvider> filterCaptor =
+ ArgumentCaptor.forClass(AppEntryListManager.AppFilterProvider.class);
+ verify(mAppEntryListManager).init(any(), filterCaptor.capture(), any());
+ ApplicationsState.AppFilter filter = filterCaptor.getValue().getAppFilter();
AppEntry systemApp = createAppEntry("test.package", /* uid= */ 1, /* isOpPermissible= */
false);
@@ -312,18 +247,13 @@
}
@Test
- public void rebuildFilter_notShowingSystemApps_removesSystemEntries() {
+ public void appFilter_notShowingSystemApps_removesSystemEntries() {
mControllerHelper.markState(Lifecycle.State.STARTED);
- ApplicationsState.Callbacks callbacks = mCallbackCaptor.getAllValues().get(0);
- callbacks.onLoadEntriesCompleted();
- ArgumentCaptor<ApplicationsState.AppFilter> filterCaptor = ArgumentCaptor.forClass(
- ApplicationsState.AppFilter.class);
- verify(mSession).rebuild(filterCaptor.capture(),
- eq(ApplicationsState.ALPHA_COMPARATOR), /* foreground= */
- eq(false));
-
- // Not showing system by default
- ApplicationsState.AppFilter filter = filterCaptor.getValue();
+ // Not showing system by default.
+ ArgumentCaptor<AppEntryListManager.AppFilterProvider> filterCaptor =
+ ArgumentCaptor.forClass(AppEntryListManager.AppFilterProvider.class);
+ verify(mAppEntryListManager).init(any(), filterCaptor.capture(), any());
+ ApplicationsState.AppFilter filter = filterCaptor.getValue().getAppFilter();
AppEntry systemApp = createAppEntry("test.package", /* uid= */ 1, /* isOpPermissible= */
false);
@@ -333,17 +263,12 @@
}
@Test
- public void rebuildFilter_removesNullExtraInfoEntries() {
+ public void appFilter_removesNullExtraInfoEntries() {
mControllerHelper.markState(Lifecycle.State.STARTED);
- ApplicationsState.Callbacks callbacks = mCallbackCaptor.getAllValues().get(0);
- callbacks.onLoadEntriesCompleted();
- ArgumentCaptor<ApplicationsState.AppFilter> filterCaptor = ArgumentCaptor.forClass(
- ApplicationsState.AppFilter.class);
- verify(mSession).rebuild(filterCaptor.capture(),
- eq(ApplicationsState.ALPHA_COMPARATOR), /* foreground= */
- eq(false));
-
- ApplicationsState.AppFilter filter = filterCaptor.getValue();
+ ArgumentCaptor<AppEntryListManager.AppFilterProvider> filterCaptor =
+ ArgumentCaptor.forClass(AppEntryListManager.AppFilterProvider.class);
+ verify(mAppEntryListManager).init(any(), filterCaptor.capture(), any());
+ ApplicationsState.AppFilter filter = filterCaptor.getValue().getAppFilter();
AppEntry appEntry = createAppEntry("test.package", /* uid= */ 1, /* isOpPermissible= */
false);
diff --git a/tests/robotests/src/com/android/car/settings/applications/specialaccess/AppStateAppOpsBridgeTest.java b/tests/robotests/src/com/android/car/settings/applications/specialaccess/AppStateAppOpsBridgeTest.java
index 8c75c7c..718edde 100644
--- a/tests/robotests/src/com/android/car/settings/applications/specialaccess/AppStateAppOpsBridgeTest.java
+++ b/tests/robotests/src/com/android/car/settings/applications/specialaccess/AppStateAppOpsBridgeTest.java
@@ -18,7 +18,6 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -31,7 +30,6 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
-import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -39,7 +37,6 @@
import com.android.car.settings.CarSettingsRobolectricTestRunner;
import com.android.car.settings.applications.specialaccess.AppStateAppOpsBridge.PermissionState;
import com.android.car.settings.testutils.ShadowAppOpsManager;
-import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import org.junit.Before;
@@ -54,6 +51,7 @@
import org.robolectric.shadows.ShadowUserManager;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -68,16 +66,11 @@
@Mock
private IPackageManager mIPackageManager;
@Mock
- private ApplicationsState mApplicationsState;
- @Mock
- private ApplicationsState.Session mSession;
- @Mock
private ParceledListSlice<PackageInfo> mParceledPackages;
@Mock
private ParceledListSlice<PackageInfo> mParceledPackagesOtherProfile;
private List<PackageInfo> mPackages;
- private ArrayList<AppEntry> mAppEntries;
private Context mContext;
private AppOpsManager mAppOpsManager;
@@ -94,15 +87,9 @@
.thenReturn(mParceledPackages);
when(mParceledPackages.getList()).thenReturn(mPackages);
- mAppEntries = new ArrayList<>();
- when(mApplicationsState.newSession(any())).thenReturn(mSession);
- when(mApplicationsState.getBackgroundLooper()).thenReturn(Looper.getMainLooper());
- when(mSession.getAllApps()).thenReturn(mAppEntries);
-
mContext = RuntimeEnvironment.application;
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
- mBridge = new AppStateAppOpsBridge(mContext, mApplicationsState, APP_OP_CODE, PERMISSION,
- mock(AppStateBaseBridge.Callback.class), mIPackageManager);
+ mBridge = new AppStateAppOpsBridge(mContext, APP_OP_CODE, PERMISSION, mIPackageManager);
}
@Test
@@ -111,11 +98,9 @@
int uid = UserHandle.getUid(UserHandle.myUserId(), /* appId= */ 1);
PackageInfo packageInfo = createPackageInfo(packageName, uid);
addPackageWithPermission(packageInfo, AppOpsManager.MODE_ALLOWED);
- addEntry(packageInfo);
+ AppEntry entry = createAppEntry(packageInfo);
- AppEntry entry = mAppEntries.get(0);
-
- mBridge.start();
+ mBridge.loadExtraInfo(Collections.singletonList(entry));
assertThat(entry.extraInfo).isNull();
}
@@ -126,11 +111,9 @@
int uid = UserHandle.getUid(UserHandle.myUserId(), /* appId= */ 1);
PackageInfo packageInfo = createPackageInfo(packageName, uid);
addPackageWithPermission(packageInfo, AppOpsManager.MODE_ALLOWED);
- addEntry(packageInfo);
+ AppEntry entry = createAppEntry(packageInfo);
- AppEntry entry = mAppEntries.get(0);
-
- mBridge.start();
+ mBridge.loadExtraInfo(Collections.singletonList(entry));
assertThat(entry.extraInfo).isNull();
}
@@ -144,11 +127,9 @@
mPackages.add(packageInfo);
when(mIPackageManager.isPackageAvailable(packageInfo.packageName,
UserHandle.myUserId())).thenReturn(true);
- addEntry(packageInfo);
+ AppEntry entry = createAppEntry(packageInfo);
- AppEntry entry = mAppEntries.get(0);
-
- mBridge.start();
+ mBridge.loadExtraInfo(Collections.singletonList(entry));
assertThat(entry.extraInfo).isNull();
}
@@ -159,14 +140,11 @@
int uid = UserHandle.getUid(UserHandle.myUserId(), /* appId= */ 1);
PackageInfo packageInfo = createPackageInfo(packageName, uid);
addPackageWithPermission(packageInfo, AppOpsManager.MODE_ALLOWED);
- addEntry(packageInfo);
-
when(mIPackageManager.isPackageAvailable(packageInfo.packageName,
UserHandle.myUserId())).thenReturn(false);
+ AppEntry entry = createAppEntry(packageInfo);
- AppEntry entry = mAppEntries.get(0);
-
- mBridge.start();
+ mBridge.loadExtraInfo(Collections.singletonList(entry));
assertThat(entry.extraInfo).isNull();
}
@@ -177,12 +155,10 @@
int uid = UserHandle.getUid(UserHandle.myUserId(), /* appId= */ 1);
PackageInfo packageInfo = createPackageInfo(packageName, uid);
addPackageWithPermission(packageInfo, AppOpsManager.MODE_ALLOWED);
- addEntry(packageInfo);
-
- AppEntry entry = mAppEntries.get(0);
+ AppEntry entry = createAppEntry(packageInfo);
assertThat(entry.extraInfo).isNull();
- mBridge.start();
+ mBridge.loadExtraInfo(Collections.singletonList(entry));
assertThat(entry.extraInfo).isNotNull();
assertThat(((PermissionState) entry.extraInfo).isPermissible()).isTrue();
@@ -194,12 +170,10 @@
int uid = UserHandle.getUid(UserHandle.myUserId(), /* appId= */ 1);
PackageInfo packageInfo = createPackageInfo(packageName, uid);
addPackageWithPermission(packageInfo, AppOpsManager.MODE_DEFAULT);
- addEntry(packageInfo);
-
- AppEntry entry = mAppEntries.get(0);
+ AppEntry entry = createAppEntry(packageInfo);
assertThat(entry.extraInfo).isNull();
- mBridge.start();
+ mBridge.loadExtraInfo(Collections.singletonList(entry));
assertThat(entry.extraInfo).isNotNull();
assertThat(((PermissionState) entry.extraInfo).isPermissible()).isTrue();
@@ -211,12 +185,10 @@
int uid = UserHandle.getUid(UserHandle.myUserId(), /* appId= */ 1);
PackageInfo packageInfo = createPackageInfo(packageName, uid);
addPackageWithPermission(packageInfo, AppOpsManager.MODE_IGNORED);
- addEntry(packageInfo);
-
- AppEntry entry = mAppEntries.get(0);
+ AppEntry entry = createAppEntry(packageInfo);
assertThat(entry.extraInfo).isNull();
- mBridge.start();
+ mBridge.loadExtraInfo(Collections.singletonList(entry));
assertThat(entry.extraInfo).isNotNull();
assertThat(((PermissionState) entry.extraInfo).isPermissible()).isFalse();
@@ -228,18 +200,15 @@
int uid1 = UserHandle.getUid(UserHandle.myUserId(), /* appId= */ 1);
PackageInfo packageInfo1 = createPackageInfo(packageName1, uid1);
addPackageWithPermission(packageInfo1, AppOpsManager.MODE_ALLOWED);
- addEntry(packageInfo1);
+ AppEntry entry1 = createAppEntry(packageInfo1);
String packageName2 = "test.package2";
int uid2 = UserHandle.getUid(UserHandle.myUserId(), /* appId= */ 2);
PackageInfo packageInfo2 = createPackageInfo(packageName2, uid2);
addPackageWithPermission(packageInfo2, AppOpsManager.MODE_ALLOWED);
- addEntry(packageInfo2);
+ AppEntry entry2 = createAppEntry(packageInfo2);
- AppEntry entry1 = mAppEntries.get(0);
- AppEntry entry2 = mAppEntries.get(1);
-
- mBridge.start();
+ mBridge.loadExtraInfo(Arrays.asList(entry1, entry2));
assertThat(entry1.extraInfo).isNotNull();
assertThat(entry2.extraInfo).isNotNull();
@@ -251,7 +220,7 @@
int uid1 = UserHandle.getUid(UserHandle.myUserId(), /* appId= */ 1);
PackageInfo packageInfo1 = createPackageInfo(packageName1, uid1);
addPackageWithPermission(packageInfo1, AppOpsManager.MODE_ALLOWED);
- addEntry(packageInfo1);
+ AppEntry entry1 = createAppEntry(packageInfo1);
// Add a package for another profile.
int otherUserId = UserHandle.myUserId() + 1;
@@ -269,17 +238,13 @@
otherUserId)).thenReturn(true);
mAppOpsManager.setMode(APP_OP_CODE, packageInfo2.applicationInfo.uid,
packageInfo2.packageName, AppOpsManager.MODE_ALLOWED);
- addEntry(packageInfo2);
-
- AppEntry entry1 = mAppEntries.get(0);
- AppEntry entry2 = mAppEntries.get(1);
+ AppEntry entry2 = createAppEntry(packageInfo2);
getShadowUserManager().addUserProfile(UserHandle.of(otherUserId));
// Recreate the bridge so it has all user profiles.
- mBridge = new AppStateAppOpsBridge(mContext, mApplicationsState, APP_OP_CODE, PERMISSION,
- mock(AppStateBaseBridge.Callback.class), mIPackageManager);
+ mBridge = new AppStateAppOpsBridge(mContext, APP_OP_CODE, PERMISSION, mIPackageManager);
- mBridge.start();
+ mBridge.loadExtraInfo(Arrays.asList(entry1, entry2));
assertThat(entry1.extraInfo).isNotNull();
assertThat(entry2.extraInfo).isNotNull();
@@ -290,12 +255,10 @@
String packageName = "test.package";
int uid = UserHandle.getUid(UserHandle.myUserId(), /* appId= */ 1);
PackageInfo packageInfo = createPackageInfo(packageName, uid);
- addEntry(packageInfo);
-
- AppEntry entry = mAppEntries.get(0);
+ AppEntry entry = createAppEntry(packageInfo);
entry.extraInfo = new Object();
- mBridge.start();
+ mBridge.loadExtraInfo(Collections.singletonList(entry));
assertThat(entry.extraInfo).isNull();
}
@@ -322,10 +285,10 @@
packageInfo.packageName, mode);
}
- private void addEntry(PackageInfo packageInfo) {
+ private AppEntry createAppEntry(PackageInfo packageInfo) {
AppEntry appEntry = mock(AppEntry.class);
appEntry.info = packageInfo.applicationInfo;
- mAppEntries.add(appEntry);
+ return appEntry;
}
private ShadowUserManager getShadowUserManager() {
diff --git a/tests/robotests/src/com/android/car/settings/applications/specialaccess/AppStateBaseBridgeTest.java b/tests/robotests/src/com/android/car/settings/applications/specialaccess/AppStateBaseBridgeTest.java
deleted file mode 100644
index 1f910dc..0000000
--- a/tests/robotests/src/com/android/car/settings/applications/specialaccess/AppStateBaseBridgeTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2019 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.car.settings.applications.specialaccess;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.os.Looper;
-
-import com.android.car.settings.CarSettingsRobolectricTestRunner;
-import com.android.settingslib.applications.ApplicationsState;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** Unit test for {@link AppStateBaseBridge}. */
-@RunWith(CarSettingsRobolectricTestRunner.class)
-public class AppStateBaseBridgeTest {
-
- @Mock
- private ApplicationsState mApplicationsState;
- @Mock
- private ApplicationsState.Session mSession;
- @Mock
- private AppStateBaseBridge.Callback mCallback;
- @Captor
- private ArgumentCaptor<ApplicationsState.Callbacks> mSessionCallbacksCaptor;
-
- private TestAppStateBaseBridge mBridge;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mApplicationsState.newSession(mSessionCallbacksCaptor.capture())).thenReturn(mSession);
- when(mApplicationsState.getBackgroundLooper()).thenReturn(Looper.getMainLooper());
-
- mBridge = new TestAppStateBaseBridge(mApplicationsState, mCallback);
- }
-
- @Test
- public void start_resumesSession() {
- mBridge.start();
-
- verify(mSession).onResume();
- }
-
- @Test
- public void start_beginsLoadingExtraInfo() {
- mBridge.start();
-
- assertThat(mBridge.getLoadExtraInfoCalledCount()).isEqualTo(1);
- }
-
- @Test
- public void onPackageListChanged_beginsLoadingExtraInfo() {
- mSessionCallbacksCaptor.getValue().onPackageListChanged();
-
- assertThat(mBridge.getLoadExtraInfoCalledCount()).isEqualTo(1);
- }
-
- @Test
- public void onLoadEntriesCompleted_beginsLoadingExtraInfo() {
- mSessionCallbacksCaptor.getValue().onLoadEntriesCompleted();
-
- assertThat(mBridge.getLoadExtraInfoCalledCount()).isEqualTo(1);
- }
-
- @Test
- public void stop_pausesSession() {
- mBridge.stop();
-
- verify(mSession).onPause();
- }
-
- @Test
- public void destroy_destroysSession() {
- mBridge.destroy();
-
- verify(mSession).onDestroy();
- }
-
- @Test
- public void forceUpdate_updatesEntryExtraInfo() {
- ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class);
- mBridge.forceUpdate(entry);
-
- assertThat(mBridge.getArgsForLoadExtraInfo(/* forNthCall= */ 0)).containsExactly(entry);
- }
-
- @Test
- public void extraInfoLoaded_callbackNotified() {
- // Start loading.
- mBridge.start();
-
- // Everything is on the same looper in the test env, so loading will finish immediately.
- verify(mCallback).onExtraInfoUpdated();
- }
-
- /** Concrete impl of base class for testing. */
- private static class TestAppStateBaseBridge extends AppStateBaseBridge {
-
- private int mLoadExtraInfoCalledCount;
- private List<List<ApplicationsState.AppEntry>> mLoadExtraInfoArgs = new ArrayList<>();
-
- TestAppStateBaseBridge(ApplicationsState applicationsState, Callback callback) {
- super(applicationsState, callback);
- }
-
- @Override
- protected void loadExtraInfo(List<ApplicationsState.AppEntry> entries) {
- mLoadExtraInfoCalledCount++;
- mLoadExtraInfoArgs.add(entries);
- }
-
- int getLoadExtraInfoCalledCount() {
- return mLoadExtraInfoCalledCount;
- }
-
- List<ApplicationsState.AppEntry> getArgsForLoadExtraInfo(int forNthCall) {
- return mLoadExtraInfoArgs.get(forNthCall);
- }
- }
-}
diff --git a/tests/robotests/src/com/android/car/settings/testutils/ShadowActivityThread.java b/tests/robotests/src/com/android/car/settings/testutils/ShadowActivityThread.java
index 2d51a86..5cd1ac6 100644
--- a/tests/robotests/src/com/android/car/settings/testutils/ShadowActivityThread.java
+++ b/tests/robotests/src/com/android/car/settings/testutils/ShadowActivityThread.java
@@ -25,29 +25,14 @@
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
-import org.robolectric.annotation.Resetter;
import java.lang.reflect.Proxy;
@Implements(ActivityThread.class)
public class ShadowActivityThread {
- private static IPackageManager sIPackageManager;
-
- public static void setPackageManager(IPackageManager packageManager) {
- sIPackageManager = packageManager;
- }
-
- @Resetter
- public static void reset() {
- sIPackageManager = null;
- }
-
@Implementation
protected static IPackageManager getPackageManager() {
- if (sIPackageManager != null) {
- return sIPackageManager;
- }
ClassLoader classLoader = ShadowActivityThread.class.getClassLoader();
Class<?> iPackageManagerClass;
try {
diff --git a/tests/robotests/src/com/android/car/settings/testutils/ShadowCarWifiManager.java b/tests/robotests/src/com/android/car/settings/testutils/ShadowCarWifiManager.java
index 8215a8b..e07116a 100644
--- a/tests/robotests/src/com/android/car/settings/testutils/ShadowCarWifiManager.java
+++ b/tests/robotests/src/com/android/car/settings/testutils/ShadowCarWifiManager.java
@@ -29,7 +29,7 @@
import java.util.List;
-/**TODO: Refactor all methods to run without relying on sInstance. */
+/** TODO: Refactor all methods to run without relying on sInstance. */
@Implements(CarWifiManager.class)
public class ShadowCarWifiManager {
@@ -126,6 +126,12 @@
}
@Implementation
+ protected void connectToSavedWifi(AccessPoint accessPoint,
+ WifiManager.ActionListener listener) {
+ sInstance.connectToSavedWifi(accessPoint, listener);
+ }
+
+ @Implementation
protected boolean isDualModeSupported() {
return sIsDualModeSupported;
}