diff options
| author | 2018-01-29 09:52:15 -0500 | |
|---|---|---|
| committer | 2018-01-31 14:38:23 -0500 | |
| commit | 4bd8e05c1dbae46d94b731241252ddccff6d977c (patch) | |
| tree | 9a3a5c84a7ac7c65c5c37771b7db79302af66e39 | |
| parent | b7158102ba903b65586e0cbd4a745967e17bf8f8 (diff) | |
Add alarm tile to QS.
- Add an alarm tile to QS
- Add the tile to QS the first time the user creates an alarm
- Tapping on the tile navigates to alarm settings
- Added unit tests for alarm tile
- Updated AutoAddTracker to remove deprecated shared preferences values
so the keys can be removed in a later release
Bug: 70799533
Test: manual testing the alarm QS tile behavior
Change-Id: I2b10468c41b4720b66c9e7bb32e22eb958c199f7
9 files changed, 206 insertions, 30 deletions
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 1cc1cc883268..ae910fe57089 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -124,7 +124,7 @@ <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" --> <string name="quick_settings_tiles_stock" translatable="false"> - wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night + wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night,alarm </string> <!-- The tiles to display in QuickSettings --> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 72615ce690e5..5557f8eda005 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -739,6 +739,8 @@ <string name="quick_settings_wifi_on_label">Wi-Fi On</string> <!-- QuickSettings: Wifi detail panel, text when there are no items [CHAR LIMIT=NONE] --> <string name="quick_settings_wifi_detail_empty_text">No Wi-Fi networks available</string> + <!-- QuickSettings: Alarm title [CHAR LIMIT=NONE] --> + <string name="quick_settings_alarm_title">Alarm</string> <!-- QuickSettings: Cast title [CHAR LIMIT=NONE] --> <string name="quick_settings_cast_title">Cast</string> <!-- QuickSettings: Cast detail panel, status text when casting [CHAR LIMIT=NONE] --> diff --git a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java index f960dc5b4a47..2a2bc0923e1b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java +++ b/packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.java @@ -51,10 +51,11 @@ public class AutoAddTracker { public AutoAddTracker(Context context) { mContext = context; mAutoAdded = new ArraySet<>(getAdded()); + // TODO: remove migration code and shared preferences keys after P release for (String[] convertPref : CONVERT_PREFS) { if (Prefs.getBoolean(context, convertPref[0], false)) { setTileAdded(convertPref[1]); - Prefs.putBoolean(context, convertPref[0], false); + Prefs.remove(context, convertPref[0]); } } mContext.getContentResolver().registerContentObserver( diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java index 77c3bfab8de9..bf9746eafaf0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java @@ -23,6 +23,7 @@ import com.android.systemui.plugins.qs.*; import com.android.systemui.plugins.qs.QSTileView; import com.android.systemui.qs.external.CustomTile; import com.android.systemui.qs.tiles.AirplaneModeTile; +import com.android.systemui.qs.tiles.AlarmTile; import com.android.systemui.qs.tiles.BatterySaverTile; import com.android.systemui.qs.tiles.BluetoothTile; import com.android.systemui.qs.tiles.CastTile; @@ -69,6 +70,7 @@ public class QSFactoryImpl implements QSFactory { else if (tileSpec.equals("saver")) return new DataSaverTile(mHost); else if (tileSpec.equals("night")) return new NightDisplayTile(mHost); else if (tileSpec.equals("nfc")) return new NfcTile(mHost); + else if (tileSpec.equals("alarm")) return new AlarmTile(mHost); // Intent tiles. else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(mHost, tileSpec); else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(mHost, tileSpec); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.java new file mode 100644 index 000000000000..ff3fe731ad4f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2018 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.qs.tiles; + +import static android.service.quicksettings.Tile.STATE_ACTIVE; +import static android.service.quicksettings.Tile.STATE_UNAVAILABLE; + +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.QS_ALARM; +import static com.android.systemui.keyguard.KeyguardSliceProvider.formatNextAlarm; + +import android.app.AlarmManager.AlarmClockInfo; +import android.app.PendingIntent; +import android.content.Intent; +import android.provider.AlarmClock; + +import com.android.systemui.Dependency; +import com.android.systemui.R; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.qs.QSTileHost; +import com.android.systemui.qs.tileimpl.QSTileImpl; +import com.android.systemui.statusbar.policy.NextAlarmController; +import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; + +public class AlarmTile extends QSTileImpl implements NextAlarmChangeCallback { + private final NextAlarmController mController; + private String mNextAlarm; + private PendingIntent mIntent; + + public AlarmTile(QSTileHost host) { + super(host); + mController = Dependency.get(NextAlarmController.class); + } + + @Override + public State newTileState() { + return new BooleanState(); + } + + @Override + protected void handleClick() { + if (mIntent != null) { + Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(mIntent); + } + } + + @Override + protected void handleUpdateState(State state, Object arg) { + state.state = mNextAlarm != null ? STATE_ACTIVE : STATE_UNAVAILABLE; + state.label = getTileLabel(); + state.secondaryLabel = mNextAlarm; + state.icon = ResourceIcon.get(R.drawable.stat_sys_alarm); + ((BooleanState) state).value = mNextAlarm != null; + } + + @Override + public void onNextAlarmChanged(AlarmClockInfo nextAlarm) { + if (nextAlarm != null) { + mNextAlarm = formatNextAlarm(mContext, nextAlarm); + mIntent = nextAlarm.getShowIntent(); + } else { + mNextAlarm = null; + mIntent = null; + } + refreshState(); + } + + @Override + public int getMetricsCategory() { + return QS_ALARM; + } + + @Override + public Intent getLongClickIntent() { + return new Intent(AlarmClock.ACTION_SET_ALARM); + } + + @Override + protected void handleSetListening(boolean listening) { + if (listening) { + mController.addCallback(this); + } else { + mController.removeCallback(this); + } + } + + @Override + public CharSequence getTileLabel() { + return mContext.getString(R.string.status_bar_alarm); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java index 36f9f6b79417..b220686b3056 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java @@ -14,16 +14,13 @@ package com.android.systemui.statusbar.phone; +import android.app.AlarmManager.AlarmClockInfo; import android.content.Context; import android.os.Handler; -import android.os.Looper; import android.provider.Settings.Secure; - import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ColorDisplayController; import com.android.systemui.Dependency; -import com.android.systemui.Prefs; -import com.android.systemui.Prefs.Key; import com.android.systemui.qs.AutoAddTracker; import com.android.systemui.qs.QSTileHost; import com.android.systemui.qs.SecureSetting; @@ -31,27 +28,37 @@ import com.android.systemui.statusbar.policy.DataSaverController; import com.android.systemui.statusbar.policy.DataSaverController.Listener; import com.android.systemui.statusbar.policy.HotspotController; import com.android.systemui.statusbar.policy.HotspotController.Callback; +import com.android.systemui.statusbar.policy.NextAlarmController; +import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; /** * Manages which tiles should be automatically added to QS. */ public class AutoTileManager { - public static final String HOTSPOT = "hotspot"; public static final String SAVER = "saver"; public static final String INVERSION = "inversion"; public static final String WORK = "work"; public static final String NIGHT = "night"; + public static final String ALARM = "alarm"; + private final Context mContext; private final QSTileHost mHost; private final Handler mHandler; private final AutoAddTracker mAutoTracker; public AutoTileManager(Context context, QSTileHost host) { - mAutoTracker = new AutoAddTracker(context); + this(context, new AutoAddTracker(context), host, + new Handler(Dependency.get(Dependency.BG_LOOPER))); + } + + @VisibleForTesting + AutoTileManager(Context context, AutoAddTracker autoAddTracker, QSTileHost host, + Handler handler) { + mAutoTracker = autoAddTracker; mContext = context; mHost = host; - mHandler = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER)); + mHandler = handler; if (!mAutoTracker.isAdded(HOTSPOT)) { Dependency.get(HotspotController.class).addCallback(mHotspotCallback); } @@ -76,20 +83,25 @@ public class AutoTileManager { if (!mAutoTracker.isAdded(WORK)) { Dependency.get(ManagedProfileController.class).addCallback(mProfileCallback); } - if (!mAutoTracker.isAdded(NIGHT) - && ColorDisplayController.isAvailable(mContext)) { + && ColorDisplayController.isAvailable(mContext)) { Dependency.get(ColorDisplayController.class).setListener(mColorDisplayCallback); } + if (!mAutoTracker.isAdded(ALARM)) { + Dependency.get(NextAlarmController.class).addCallback(mNextAlarmChangeCallback); + } } public void destroy() { - mColorsSetting.setListening(false); + if (mColorsSetting != null) { + mColorsSetting.setListening(false); + } mAutoTracker.destroy(); Dependency.get(HotspotController.class).removeCallback(mHotspotCallback); Dependency.get(DataSaverController.class).removeCallback(mDataSaverListener); Dependency.get(ManagedProfileController.class).removeCallback(mProfileCallback); Dependency.get(ColorDisplayController.class).setListener(null); + Dependency.get(NextAlarmController.class).removeCallback(mNextAlarmChangeCallback); } private final ManagedProfileController.Callback mProfileCallback = @@ -138,6 +150,19 @@ public class AutoTileManager { } }; + private final NextAlarmChangeCallback mNextAlarmChangeCallback = new NextAlarmChangeCallback() { + @Override + public void onNextAlarmChanged(AlarmClockInfo nextAlarm) { + if (mAutoTracker.isAdded(ALARM)) return; + if (nextAlarm != null) { + mHost.addTile(ALARM); + mAutoTracker.setTileAdded(ALARM); + mHandler.post(() -> Dependency.get(NextAlarmController.class) + .removeCallback(mNextAlarmChangeCallback)); + } + } + }; + @VisibleForTesting final ColorDisplayController.Callback mColorDisplayCallback = new ColorDisplayController.Callback() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java index 40f8059fecbf..dfc1852502e2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/AutoAddTrackerTest.java @@ -30,6 +30,7 @@ import com.android.systemui.Prefs; import com.android.systemui.Prefs.Key; import com.android.systemui.SysuiTestCase; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -40,6 +41,11 @@ public class AutoAddTrackerTest extends SysuiTestCase { private AutoAddTracker mAutoTracker; + @Before + public void setUp() { + Secure.putString(mContext.getContentResolver(), Secure.QS_AUTO_ADDED_TILES, ""); + } + @Test public void testMigration() { Prefs.putBoolean(mContext, Key.QS_DATA_SAVER_ADDED, true); @@ -50,7 +56,10 @@ public class AutoAddTrackerTest extends SysuiTestCase { assertTrue(mAutoTracker.isAdded(WORK)); assertFalse(mAutoTracker.isAdded(INVERSION)); + // These keys have been removed; retrieving their values should always return the default. + assertTrue(Prefs.getBoolean(mContext, Key.QS_DATA_SAVER_ADDED, true )); assertFalse(Prefs.getBoolean(mContext, Key.QS_DATA_SAVER_ADDED, false)); + assertTrue(Prefs.getBoolean(mContext, Key.QS_WORK_ADDED, true)); assertFalse(Prefs.getBoolean(mContext, Key.QS_WORK_ADDED, false)); mAutoTracker.destroy(); @@ -96,5 +105,4 @@ public class AutoAddTrackerTest extends SysuiTestCase { mAutoTracker.destroy(); } - }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java index a95e3dbb1e3b..2d2db1bba735 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java @@ -18,45 +18,48 @@ package com.android.systemui.statusbar.phone; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.app.AlarmManager.AlarmClockInfo; +import android.os.Handler; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; - import com.android.internal.app.ColorDisplayController; import com.android.systemui.Dependency; -import com.android.systemui.Prefs; -import com.android.systemui.Prefs.Key; import com.android.systemui.SysuiTestCase; +import com.android.systemui.qs.AutoAddTracker; import com.android.systemui.qs.QSTileHost; - -import org.junit.After; +import com.android.systemui.statusbar.policy.NextAlarmController; +import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mockito; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) @RunWithLooper @SmallTest public class AutoTileManagerTest extends SysuiTestCase { - private QSTileHost mQsTileHost; + @Mock private QSTileHost mQsTileHost; + @Mock private AutoAddTracker mAutoAddTracker; + @Captor private ArgumentCaptor<NextAlarmChangeCallback> mAlarmCallback; + private AutoTileManager mAutoTileManager; @Before public void setUp() throws Exception { - mDependency.injectTestDependency(Dependency.BG_LOOPER, - TestableLooper.get(this).getLooper()); - Prefs.putBoolean(mContext, Key.QS_NIGHTDISPLAY_ADDED, false); - mQsTileHost = Mockito.mock(QSTileHost.class); - mAutoTileManager = new AutoTileManager(mContext, mQsTileHost); - } - - @After - public void tearDown() throws Exception { - mAutoTileManager = null; + MockitoAnnotations.initMocks(this); + mDependency.injectMockDependency(NextAlarmController.class); + mAutoTileManager = new AutoTileManager(mContext, mAutoAddTracker, + mQsTileHost, new Handler(TestableLooper.get(this).getLooper())); + verify(Dependency.get(NextAlarmController.class)) + .addCallback(mAlarmCallback.capture()); } @Test @@ -106,4 +109,30 @@ public class AutoTileManagerTest extends SysuiTestCase { ColorDisplayController.AUTO_MODE_DISABLED); verify(mQsTileHost, never()).addTile("night"); } + + @Test + public void alarmTileAdded_whenAlarmSet() { + mAlarmCallback.getValue().onNextAlarmChanged(new AlarmClockInfo(0, null)); + + verify(mQsTileHost).addTile("alarm"); + verify(mAutoAddTracker).setTileAdded("alarm"); + } + + @Test + public void alarmTileNotAdded_whenAlarmNotSet() { + mAlarmCallback.getValue().onNextAlarmChanged(null); + + verify(mQsTileHost, never()).addTile("alarm"); + verify(mAutoAddTracker, never()).setTileAdded("alarm"); + } + + @Test + public void alarmTileNotAdded_whenAlreadyAdded() { + when(mAutoAddTracker.isAdded("alarm")).thenReturn(true); + + mAlarmCallback.getValue().onNextAlarmChanged(new AlarmClockInfo(0, null)); + + verify(mQsTileHost, never()).addTile("alarm"); + verify(mAutoAddTracker, never()).setTileAdded("alarm"); + } } diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 7539d8847c2d..a2d69a80b71e 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -5173,6 +5173,13 @@ message MetricsEvent { // OS: P AUTOFILL_INVALID_PERMISSION = 1289; + // OPEN: QS Alarm tile shown + // ACTION: QS Alarm tile tapped + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: QUICK_SETTINGS + // OS: P + QS_ALARM = 1290; + // ---- End P Constants, all P constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS |