summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/BootCompleteCache.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/BootCompleteCacheImpl.kt116
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIApplication.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt119
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java4
9 files changed, 298 insertions, 16 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/BootCompleteCache.kt b/packages/SystemUI/src/com/android/systemui/BootCompleteCache.kt
new file mode 100644
index 000000000000..c6bdb30fb804
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/BootCompleteCache.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 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.systemui
+
+interface BootCompleteCache {
+ fun isBootComplete(): Boolean
+ fun addListener(listener: BootCompleteListener): Boolean
+ fun removeListener(listener: BootCompleteListener)
+
+ interface BootCompleteListener {
+ fun onBootComplete()
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/BootCompleteCacheImpl.kt b/packages/SystemUI/src/com/android/systemui/BootCompleteCacheImpl.kt
new file mode 100644
index 000000000000..310393bb46eb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/BootCompleteCacheImpl.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 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.systemui
+
+import android.util.Log
+import com.android.internal.annotations.GuardedBy
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import java.lang.ref.WeakReference
+import java.util.concurrent.atomic.AtomicBoolean
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * Caches whether the device has reached [SystemService.PHASE_BOOT_COMPLETED].
+ *
+ * This class is constructed and set by [SystemUIApplication] and will notify all listeners when
+ * boot is completed.
+ */
+@Singleton
+class BootCompleteCacheImpl @Inject constructor(private val dumpController: DumpController) :
+ BootCompleteCache, Dumpable {
+
+ companion object {
+ private const val TAG = "BootCompleteCacheImpl"
+ private const val DEBUG = false
+ }
+
+ init {
+ dumpController.registerDumpable(TAG, this)
+ }
+
+ @GuardedBy("listeners")
+ private val listeners = mutableListOf<WeakReference<BootCompleteCache.BootCompleteListener>>()
+ private val bootComplete = AtomicBoolean(false)
+
+ /**
+ * Provides the current boot state of the system as determined by [SystemUIApplication].
+ * @return `true` if the system has reached [SystemService.PHASE_BOOT_COMPLETED]
+ */
+ override fun isBootComplete(): Boolean = bootComplete.get()
+
+ /**
+ * Indicates to this object that boot is complete. Subsequent calls to this function will have
+ * no effect.
+ */
+ fun setBootComplete() {
+ if (bootComplete.compareAndSet(false, true)) {
+ if (DEBUG) Log.d(TAG, "Boot complete set")
+ synchronized(listeners) {
+ listeners.forEach {
+ it.get()?.onBootComplete()
+ }
+ listeners.clear()
+ }
+ }
+ }
+
+ /**
+ * Add a listener for boot complete event. It will immediately return the current boot complete
+ * state. If this value is true, [BootCompleteCache.BootCompleteListener.onBootComplete] will
+ * never be called.
+ *
+ * @param listener a listener for boot complete state.
+ * @return `true` if boot has been completed.
+ */
+ override fun addListener(listener: BootCompleteCache.BootCompleteListener): Boolean {
+ if (bootComplete.get()) return true
+ synchronized(listeners) {
+ if (bootComplete.get()) return true
+ listeners.add(WeakReference(listener))
+ if (DEBUG) Log.d(TAG, "Adding listener: $listener")
+ return false
+ }
+ }
+
+ /**
+ * Removes a listener for boot complete event.
+ *
+ * @param listener a listener to removed.
+ */
+ override fun removeListener(listener: BootCompleteCache.BootCompleteListener) {
+ if (bootComplete.get()) return
+ synchronized(listeners) {
+ listeners.removeIf { it.get() == null || it.get() === listener }
+ if (DEBUG) Log.d(TAG, "Removing listener: $listener")
+ }
+ }
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+ pw.println("BootCompleteCache state:")
+ pw.println(" boot complete: ${isBootComplete()}")
+ if (!isBootComplete()) {
+ pw.println(" listeners:")
+ synchronized(listeners) {
+ listeners.forEach {
+ pw.println(" $it")
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 1b264e5f4515..e08de3943258 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -32,6 +32,7 @@ import android.util.Log;
import android.util.TimingsTraceLog;
import com.android.systemui.dagger.ContextComponentHelper;
+import com.android.systemui.dagger.SystemUIRootComponent;
import com.android.systemui.util.NotificationChannels;
import java.lang.reflect.Constructor;
@@ -47,13 +48,13 @@ public class SystemUIApplication extends Application implements
private static final boolean DEBUG = false;
private ContextComponentHelper mComponentHelper;
+ private BootCompleteCacheImpl mBootCompleteCache;
/**
* Hold a reference on the stuff we start.
*/
private SystemUI[] mServices;
private boolean mServicesStarted;
- private boolean mBootCompleted;
private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;
public SystemUIApplication() {
@@ -71,8 +72,9 @@ public class SystemUIApplication extends Application implements
Trace.TRACE_TAG_APP);
log.traceBegin("DependencyInjection");
mContextAvailableCallback.onContextAvailable(this);
- mComponentHelper = SystemUIFactory
- .getInstance().getRootComponent().getContextComponentHelper();
+ SystemUIRootComponent root = SystemUIFactory.getInstance().getRootComponent();
+ mComponentHelper = root.getContextComponentHelper();
+ mBootCompleteCache = root.provideBootCacheImpl();
log.traceEnd();
// Set the application theme that is inherited by all services. Note that setting the
@@ -86,19 +88,17 @@ public class SystemUIApplication extends Application implements
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (mBootCompleted) return;
+ if (mBootCompleteCache.isBootComplete()) return;
if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
unregisterReceiver(this);
- mBootCompleted = true;
+ mBootCompleteCache.setBootComplete();
if (mServicesStarted) {
final int N = mServices.length;
for (int i = 0; i < N; i++) {
mServices[i].onBootCompleted();
}
}
-
-
}
}, bootCompletedFilter);
@@ -107,7 +107,7 @@ public class SystemUIApplication extends Application implements
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
- if (!mBootCompleted) return;
+ if (!mBootCompleteCache.isBootComplete()) return;
// Update names of SystemUi notification channels
NotificationChannels.createAll(context);
}
@@ -159,11 +159,11 @@ public class SystemUIApplication extends Application implements
}
mServices = new SystemUI[services.length];
- if (!mBootCompleted) {
+ if (!mBootCompleteCache.isBootComplete()) {
// check to see if maybe it was already completed long before we began
// see ActivityManagerService.finishBooting()
if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
- mBootCompleted = true;
+ mBootCompleteCache.setBootComplete();
if (DEBUG) {
Log.v(TAG, "BOOT_COMPLETED was already sent");
}
@@ -205,7 +205,7 @@ public class SystemUIApplication extends Application implements
if (ti > 1000) {
Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
}
- if (mBootCompleted) {
+ if (mBootCompleteCache.isBootComplete()) {
mServices[i].onBootCompleted();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 617dbdfe3fcc..75063e482f08 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -57,7 +57,7 @@ public class SystemUIFactory {
private static final String TAG = "SystemUIFactory";
static SystemUIFactory mFactory;
- protected SystemUIRootComponent mRootComponent;
+ private SystemUIRootComponent mRootComponent;
public static <T extends SystemUIFactory> T getInstance() {
return (T) mFactory;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 0ac158d1b38a..9bd729edd210 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -21,6 +21,8 @@ import android.content.Context;
import android.content.pm.PackageManager;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.BootCompleteCache;
+import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.DumpController;
import com.android.systemui.assist.AssistModule;
import com.android.systemui.model.SysUiState;
@@ -52,6 +54,10 @@ import dagger.Provides;
@Module(includes = {AssistModule.class,
PeopleHubModule.class})
public abstract class SystemUIModule {
+
+ @Binds
+ abstract BootCompleteCache bindBootCompleteCache(BootCompleteCacheImpl bootCompleteCache);
+
/** */
@Binds
public abstract ContextComponentHelper bindComponentHelper(
@@ -100,4 +106,5 @@ public abstract class SystemUIModule {
@Singleton
@Binds
abstract NotifListBuilder bindNotifListBuilder(NotifListBuilderImpl impl);
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
index 3f00f41b0717..e926574977d0 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
@@ -20,6 +20,7 @@ import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME
import android.content.ContentProvider;
+import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.Dependency;
import com.android.systemui.SystemUIAppComponentFactory;
import com.android.systemui.SystemUIFactory;
@@ -48,6 +49,12 @@ import dagger.Component;
public interface SystemUIRootComponent {
/**
+ * Provides a BootCompleteCache.
+ */
+ @Singleton
+ BootCompleteCacheImpl provideBootCacheImpl();
+
+ /**
* Creates a ContextComponentHelper.
*/
@Singleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 3d51be7c02f4..d36bd75dfdba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -35,6 +35,7 @@ import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
+import com.android.systemui.BootCompleteCache;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.BgLooper;
import com.android.systemui.util.Utils;
@@ -59,6 +60,7 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
private AppOpsManager mAppOpsManager;
private StatusBarManager mStatusBarManager;
private BroadcastDispatcher mBroadcastDispatcher;
+ private BootCompleteCache mBootCompleteCache;
private boolean mAreActiveLocationRequests;
@@ -68,9 +70,10 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
@Inject
public LocationControllerImpl(Context context, @BgLooper Looper bgLooper,
- BroadcastDispatcher broadcastDispatcher) {
+ BroadcastDispatcher broadcastDispatcher, BootCompleteCache bootCompleteCache) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
+ mBootCompleteCache = bootCompleteCache;
// Register to listen for changes in location settings.
IntentFilter filter = new IntentFilter();
@@ -124,14 +127,15 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio
}
/**
- * Returns true if location is enabled in settings.
+ * Returns true if location is enabled in settings. Will return false if
+ * {@link LocationManager} service has not been completely initialized
*/
public boolean isLocationEnabled() {
// QuickSettings always runs as the owner, so specifically retrieve the settings
// for the current foreground user.
LocationManager locationManager =
(LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
- return locationManager.isLocationEnabledForUser(
+ return mBootCompleteCache.isBootComplete() && locationManager.isLocationEnabledForUser(
UserHandle.of(ActivityManager.getCurrentUser()));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt b/packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt
new file mode 100644
index 000000000000..6e79157eb582
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 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.systemui
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class BootCompleteCacheTest : SysuiTestCase() {
+
+ private lateinit var bootCompleteCache: BootCompleteCacheImpl
+ @Mock
+ private lateinit var bootCompleteListener: BootCompleteCache.BootCompleteListener
+ @Mock
+ private lateinit var dumpController: DumpController
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ bootCompleteCache = BootCompleteCacheImpl(dumpController)
+ }
+
+ @Test
+ fun testFlagChange() {
+ assertFalse(bootCompleteCache.isBootComplete())
+
+ bootCompleteCache.setBootComplete()
+
+ assertTrue(bootCompleteCache.isBootComplete())
+ }
+
+ @Test
+ fun testDoubleSetIsNoOp() {
+ assertFalse(bootCompleteCache.isBootComplete())
+
+ bootCompleteCache.setBootComplete()
+ bootCompleteCache.setBootComplete()
+
+ assertTrue(bootCompleteCache.isBootComplete())
+ }
+
+ @Test
+ fun testAddListenerGivesCurrentState_false() {
+ val boot = bootCompleteCache.addListener(bootCompleteListener)
+ assertFalse(boot)
+ }
+
+ @Test
+ fun testAddListenerGivesCurrentState_true() {
+ bootCompleteCache.setBootComplete()
+ val boot = bootCompleteCache.addListener(bootCompleteListener)
+ assertTrue(boot)
+ }
+
+ @Test
+ fun testListenerCalledOnBootComplete() {
+ bootCompleteCache.addListener(bootCompleteListener)
+
+ bootCompleteCache.setBootComplete()
+ verify(bootCompleteListener).onBootComplete()
+ }
+
+ @Test
+ fun testListenerCalledOnBootComplete_onlyOnce() {
+ bootCompleteCache.addListener(bootCompleteListener)
+
+ bootCompleteCache.setBootComplete()
+ bootCompleteCache.setBootComplete()
+
+ verify(bootCompleteListener).onBootComplete()
+ }
+
+ @Test
+ fun testListenerNotCalledIfBootIsAlreadyComplete() {
+ bootCompleteCache.setBootComplete()
+
+ bootCompleteCache.addListener(bootCompleteListener)
+
+ bootCompleteCache.setBootComplete()
+
+ verify(bootCompleteListener, never()).onBootComplete()
+ }
+
+ @Test
+ fun testListenerRemovedNotCalled() {
+ bootCompleteCache.addListener(bootCompleteListener)
+
+ bootCompleteCache.removeListener(bootCompleteListener)
+
+ bootCompleteCache.setBootComplete()
+
+ verify(bootCompleteListener, never()).onBootComplete()
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
index 5f772b2548ff..81c375a2480b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -26,6 +26,7 @@ import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
+import com.android.systemui.BootCompleteCache;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
@@ -46,7 +47,8 @@ public class LocationControllerImplTest extends SysuiTestCase {
public void setup() {
mLocationController = spy(new LocationControllerImpl(mContext,
TestableLooper.get(this).getLooper(),
- mock(BroadcastDispatcher.class)));
+ mock(BroadcastDispatcher.class),
+ mock(BootCompleteCache.class)));
}
@Test