From bf9f2d26982c89e408476af318e20b52bdd797fd Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 2 Nov 2016 11:20:17 -0700 Subject: [PATCH] Adding a customizable development mode tile User can configure the active state for development mode which would allow enabling multiple options at once Test: make -j40 RunSettingsRoboTests Change-Id: I545b790f8c7097945f39ca003e5985b23cb53636 --- AndroidManifest.xml | 25 +-- res/drawable/tile_icon_graphics.xml | 52 ----- res/drawable/tile_icon_show_layout.xml | 60 ----- res/layout/development_tile_config_header.xml | 32 +++ res/values/strings.xml | 6 + res/xml/development_tile_prefs.xml | 114 ++++++++++ .../android/settings/SettingsActivity.java | 4 +- .../settings/qstile/DevelopmentModeTile.java | 205 ++++++++++++++++++ .../qstile/DevelopmentTileConfigActivity.java | 115 ++++++++++ .../settings/qstile/DevelopmentTiles.java | 95 -------- .../grandfather_not_implementing_indexable | 3 +- .../qstile/DevelopmentModeTileTest.java | 75 +++++++ .../testutils/shadow/ShadowTileService.java | 38 ++++ 13 files changed, 601 insertions(+), 223 deletions(-) delete mode 100644 res/drawable/tile_icon_graphics.xml delete mode 100644 res/drawable/tile_icon_show_layout.xml create mode 100644 res/layout/development_tile_config_header.xml create mode 100644 res/xml/development_tile_prefs.xml create mode 100644 src/com/android/settings/qstile/DevelopmentModeTile.java create mode 100644 src/com/android/settings/qstile/DevelopmentTileConfigActivity.java delete mode 100644 src/com/android/settings/qstile/DevelopmentTiles.java create mode 100644 tests/robotests/src/com/android/settings/qstile/DevelopmentModeTileTest.java create mode 100644 tests/robotests/src/com/android/settings/testutils/shadow/ShadowTileService.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index f4a972bc8ea..d15f7a4a862 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3466,25 +3466,24 @@ + android:name=".qstile.DevelopmentModeTile" + android:label="@string/developer_tile" + android:icon="@drawable/ic_settings_development" + android:permission="android.permission.BIND_QUICK_SETTINGS_TILE" + android:enabled="true"> - + - + - + - - - - - - - - - - - diff --git a/res/drawable/tile_icon_show_layout.xml b/res/drawable/tile_icon_show_layout.xml deleted file mode 100644 index b9b825e01a6..00000000000 --- a/res/drawable/tile_icon_show_layout.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/res/layout/development_tile_config_header.xml b/res/layout/development_tile_config_header.xml new file mode 100644 index 00000000000..5169da23c05 --- /dev/null +++ b/res/layout/development_tile_config_header.xml @@ -0,0 +1,32 @@ + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 955b8ccd8fb..07d1bec10f6 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7680,6 +7680,12 @@ Smallest width + + Development mode + + + No active state selected + No installed apps have requested Premium SMS access diff --git a/res/xml/development_tile_prefs.xml b/res/xml/development_tile_prefs.xml new file mode 100644 index 00000000000..26f1c24e051 --- /dev/null +++ b/res/xml/development_tile_prefs.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index b9be118d7c9..179e3522145 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -61,7 +61,7 @@ import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.DashboardSummary; import com.android.settings.dashboard.SearchResultsSummary; import com.android.settings.overlay.FeatureFactory; -import com.android.settings.qstile.DevelopmentTiles; +import com.android.settings.qstile.DevelopmentModeTile; import com.android.settings.search.DynamicIndexableContentMonitor; import com.android.settings.search.Index; import com.android.settings.search2.SearchFeatureProvider; @@ -994,7 +994,7 @@ public class SettingsActivity extends SettingsDrawerActivity showDev, isAdmin, pm); // Reveal development-only quick settings tiles - DevelopmentTiles.setTilesEnabled(this, showDev); + setTileEnabled(new ComponentName(this, DevelopmentModeTile.class), showDev); if (UserHandle.MU_ENABLED && !isAdmin) { // When on restricted users, disable all extra categories (but only the settings ones). diff --git a/src/com/android/settings/qstile/DevelopmentModeTile.java b/src/com/android/settings/qstile/DevelopmentModeTile.java new file mode 100644 index 00000000000..578ffd8f291 --- /dev/null +++ b/src/com/android/settings/qstile/DevelopmentModeTile.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2016 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.settings.qstile; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.os.RemoteException; +import android.os.SystemProperties; +import android.provider.Settings; +import android.service.quicksettings.Tile; +import android.service.quicksettings.TileService; +import android.view.IWindowManager; +import android.view.ThreadedRenderer; +import android.view.View; + +import android.view.WindowManagerGlobal; +import com.android.internal.app.LocalePicker; +import com.android.settings.DevelopmentSettings; + +import java.util.Map; + +public class DevelopmentModeTile extends TileService { + + static final String SHARED_PREFERENCES_NAME = "development_mode_tile_settings"; + + private static final String SHOW_TOUCHES_KEY = "show_touches"; + private static final String POINTER_LOCATION_KEY = "pointer_location"; + private static final String DEBUG_LAYOUT_KEY = "debug_layout"; + private static final String FORCE_RTL_LAYOUT_KEY = "force_rtl_layout_all_locales"; + private static final String WINDOW_ANIMATION_SCALE_KEY = "window_animation_scale"; + private static final String TRANSITION_ANIMATION_SCALE_KEY = "transition_animation_scale"; + private static final String ANIMATOR_DURATION_SCALE_KEY = "animator_duration_scale"; + private static final String SHOW_HW_SCREEN_UPDATES_KEY = "show_hw_screen_udpates"; + private static final String SHOW_HW_LAYERS_UPDATES_KEY = "show_hw_layers_udpates"; + private static final String DEBUG_HW_OVERDRAW_KEY = "debug_hw_overdraw"; + private static final String TRACK_FRAME_TIME_KEY = "track_frame_time"; + + private DevModeProperties mProps = new DevModeProperties(); + + @Override + public void onStartListening() { + super.onStartListening(); + refresh(); + } + + public void refresh() { + mProps.refreshState(this); + getQsTile().setState(mProps.isSet ? (mProps.allMatch + ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE) : Tile.STATE_UNAVAILABLE); + getQsTile().updateTile(); + } + + @Override + public void onClick() { + if (getQsTile().getState() == Tile.STATE_UNAVAILABLE) { + startActivityAndCollapse(new Intent(this, DevelopmentTileConfigActivity.class)); + return; + } + + boolean active = getQsTile().getState() == Tile.STATE_INACTIVE; + Map values = + getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE).getAll(); + ContentResolver cr = getContentResolver(); + for (Property prop : mProps.mSysProps) { + Object expected = values.get(prop.prefKey); + String value = active && !prop.isDefault(expected) ? expected.toString() : "false"; + SystemProperties.set(prop.key, value); + } + for (Property prop : mProps.mSysSettings) { + boolean expectedTrue = active && !prop.isDefault(values.get(prop.prefKey)); + Settings.System.putInt(cr, prop.key, expectedTrue ? 1 : 0); + } + + boolean expectedGlobPropTrue = active && + !mProps.mGlobProp.isDefault(values.get(mProps.mGlobProp.prefKey)); + Settings.Global.putInt(cr, mProps.mGlobProp.key, expectedGlobPropTrue ? 1 : 0); + SystemProperties.set(mProps.mGlobProp.key, expectedGlobPropTrue ? "1" : "0"); + LocalePicker.updateLocales(getResources().getConfiguration().getLocales()); + + IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); + try { + // Update the various animation scale values to expected values or 1. mProps.mAnimScales + // is an ordered array, where the index corresponds to the individual property. + for (int i = 0; i < mProps.mAnimScales.length; i++) { + Object expected = values.get(mProps.mAnimScales[i]); + float expectedFloat = active && expected != null ? + Float.parseFloat(expected.toString()) : 1; + wm.setAnimationScale(i, expectedFloat); + } + } catch (RemoteException e) { } + + new DevelopmentSettings.SystemPropPoker().execute(); // Settings app magic + refresh(); + } + + static class DevModeProperties { + + private final Property[] mSysProps = new Property[] { + new Property(View.DEBUG_LAYOUT_PROPERTY, DEBUG_LAYOUT_KEY), + new Property(ThreadedRenderer.DEBUG_DIRTY_REGIONS_PROPERTY, + SHOW_HW_SCREEN_UPDATES_KEY), + new Property(ThreadedRenderer.DEBUG_SHOW_LAYERS_UPDATES_PROPERTY, + SHOW_HW_LAYERS_UPDATES_KEY), + new Property(ThreadedRenderer.DEBUG_OVERDRAW_PROPERTY, DEBUG_HW_OVERDRAW_KEY), + new Property(ThreadedRenderer.PROFILE_PROPERTY, TRACK_FRAME_TIME_KEY), + }; + + private final Property[] mSysSettings = new Property[] { + new Property(Settings.System.SHOW_TOUCHES, SHOW_TOUCHES_KEY), + new Property(Settings.System.POINTER_LOCATION, POINTER_LOCATION_KEY), + }; + + private final Property mGlobProp = + new Property(Settings.Global.DEVELOPMENT_FORCE_RTL, FORCE_RTL_LAYOUT_KEY); + + private final String[] mAnimScales = new String[] { + WINDOW_ANIMATION_SCALE_KEY, + TRANSITION_ANIMATION_SCALE_KEY, + ANIMATOR_DURATION_SCALE_KEY + }; + + /** + * True is the values of all the properties corresponds to the expected values. Updated when + * {@link #refreshState(Context)} is called. + */ + public boolean allMatch; + /** + * True is at least one property has a non-default expected value. Updated when + * {@link #refreshState(Context)} is called. Not that if all properties have default + * expected value, then active and non-active state will be the same. + */ + public boolean isSet; + + public void refreshState(Context context) { + Map values = + context.getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE).getAll(); + allMatch = true; + // True if there is at least one non-default value. + isSet = false; + + for (Property prop : mSysProps) { + Object expected = values.get(prop.prefKey); + String actual = SystemProperties.get(prop.key); + allMatch &= prop.isDefault(expected) + ? prop.isDefault(actual) : expected.toString().equals(actual); + isSet |= !prop.isDefault(expected); + } + + ContentResolver cr = context.getContentResolver(); + for (Property prop : mSysSettings) { + boolean expectedTrue = !prop.isDefault(values.get(prop.prefKey)); + isSet |= expectedTrue; + allMatch &= expectedTrue == (Settings.System.getInt(cr, prop.key, 0) != 0); + } + + boolean expectedGlopPropTrue = !mGlobProp.isDefault(values.get(mGlobProp.prefKey)); + isSet |= expectedGlopPropTrue; + allMatch &= expectedGlopPropTrue == (Settings.Global.getInt(cr, mGlobProp.key, 0) != 0); + + IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); + try { + for (int i = 0; i < mAnimScales.length; i++) { + Object expected = values.get(mAnimScales[i]); + float expectedFloat = expected == null + ? 1 : Float.parseFloat(expected.toString()); + isSet |= expectedFloat != 1; + allMatch &= expectedFloat == wm.getAnimationScale(i); + } + } catch (RemoteException e) { } + } + } + + private static class Property { + final String key; + final String prefKey; + + Property(String key, String prefKey) { + this.key = key; + this.prefKey = prefKey; + } + + boolean isDefault(Object value) { + if (value == null) { + return true; + } + String str = value.toString(); + return str.equals("") || str.equals("false"); + } + } +} diff --git a/src/com/android/settings/qstile/DevelopmentTileConfigActivity.java b/src/com/android/settings/qstile/DevelopmentTileConfigActivity.java new file mode 100644 index 00000000000..cc63026645e --- /dev/null +++ b/src/com/android/settings/qstile/DevelopmentTileConfigActivity.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2016 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.settings.qstile; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.view.View; + +import com.android.settings.R; +import com.android.settings.SettingsActivity; +import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.core.instrumentation.Instrumentable; +import com.android.settings.widget.SwitchBar; + +public class DevelopmentTileConfigActivity extends SettingsActivity { + + @Override + public Intent getIntent() { + Intent modIntent = new Intent(super.getIntent()) + .putExtra(EXTRA_SHOW_FRAGMENT, DevelopmentTileConfigFragment.class.getName()) + .putExtra(EXTRA_HIDE_DRAWER, true); + return modIntent; + } + + @Override + protected boolean isValidFragment(String fragmentName) { + return (DevelopmentTileConfigFragment.class.getName().equals(fragmentName)); + } + + public static class DevelopmentTileConfigFragment extends SettingsPreferenceFragment implements + SharedPreferences.OnSharedPreferenceChangeListener { + + private DevelopmentModeTile.DevModeProperties mProps = + new DevelopmentModeTile.DevModeProperties(); + + private SwitchBar mSwitchBar; + private View mDisabledMessage; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + getPreferenceManager() + .setSharedPreferencesName(DevelopmentModeTile.SHARED_PREFERENCES_NAME); + addPreferencesFromResource(R.xml.development_tile_prefs); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mDisabledMessage = setPinnedHeaderView(R.layout.development_tile_config_header); + refreshHeader(); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + mSwitchBar = ((SettingsActivity) getActivity()).getSwitchBar(); + mSwitchBar.setEnabled(false); + } + + @Override + public int getMetricsCategory() { + return Instrumentable.METRICS_CATEGORY_UNKNOWN; + } + + @Override + public void onResume() { + super.onResume(); + refreshHeader(); + getPreferenceManager().getSharedPreferences() + .registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onPause() { + super.onPause(); + getPreferenceManager().getSharedPreferences() + .unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + refreshHeader(); + } + + private void refreshHeader() { + if (mSwitchBar != null && mDisabledMessage != null) { + mProps.refreshState(getActivity()); + if (mProps.isSet) { + mSwitchBar.show(); + mDisabledMessage.setVisibility(View.GONE); + } else { + mSwitchBar.hide(); + mDisabledMessage.setVisibility(View.VISIBLE); + } + mSwitchBar.setChecked(mProps.allMatch); + } + } + } +} diff --git a/src/com/android/settings/qstile/DevelopmentTiles.java b/src/com/android/settings/qstile/DevelopmentTiles.java deleted file mode 100644 index 0d8e7dbec73..00000000000 --- a/src/com/android/settings/qstile/DevelopmentTiles.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2016 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.settings.qstile; - -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.SystemProperties; -import android.service.quicksettings.Tile; -import android.service.quicksettings.TileService; -import android.view.ThreadedRenderer; -import android.view.View; -import com.android.settings.DevelopmentSettings; - -public class DevelopmentTiles { - // List of components that need to be enabled when developer tools are turned on - static final Class[] TILE_CLASSES = new Class[] { - ShowLayout.class, - GPUProfiling.class, - }; - public static void setTilesEnabled(Context context, boolean enable) { - final PackageManager pm = context.getPackageManager(); - for (Class cls : TILE_CLASSES) { - pm.setComponentEnabledSetting(new ComponentName(context, cls), - enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED - : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, - PackageManager.DONT_KILL_APP); - } - } - - /** - * Tile to control the "Show layout bounds" developer setting - */ - public static class ShowLayout extends TileService { - @Override - public void onStartListening() { - super.onStartListening(); - refresh(); - } - - public void refresh() { - final boolean enabled = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false); - getQsTile().setState(enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE); - getQsTile().updateTile(); - } - - @Override - public void onClick() { - SystemProperties.set(View.DEBUG_LAYOUT_PROPERTY, - getQsTile().getState() == Tile.STATE_INACTIVE ? "true" : "false"); - new DevelopmentSettings.SystemPropPoker().execute(); // Settings app magic - refresh(); - } - } - - /** - * Tile to control the "GPU profiling" developer setting - */ - public static class GPUProfiling extends TileService { - @Override - public void onStartListening() { - super.onStartListening(); - refresh(); - } - - public void refresh() { - final String value = SystemProperties.get(ThreadedRenderer.PROFILE_PROPERTY); - getQsTile().setState(value.equals("visual_bars") - ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE); - getQsTile().updateTile(); - } - - @Override - public void onClick() { - SystemProperties.set(ThreadedRenderer.PROFILE_PROPERTY, - getQsTile().getState() == Tile.STATE_INACTIVE ? "visual_bars" : ""); - new DevelopmentSettings.SystemPropPoker().execute(); // Settings app magic - refresh(); - } - } -} \ No newline at end of file diff --git a/tests/robotests/assets/grandfather_not_implementing_indexable b/tests/robotests/assets/grandfather_not_implementing_indexable index 0c539d813d4..81adf8b7ccb 100644 --- a/tests/robotests/assets/grandfather_not_implementing_indexable +++ b/tests/robotests/assets/grandfather_not_implementing_indexable @@ -88,4 +88,5 @@ com.android.settings.notification.NotificationAccessSettings com.android.settings.notification.ZenModeSettings com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment com.android.settings.applications.ConvertToFbe -com.android.settings.localepicker.LocaleListEditor \ No newline at end of file +com.android.settings.localepicker.LocaleListEditor +com.android.settings.qstile.DevelopmentTileConfigActivity$DevelopmentTileConfigFragment \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/qstile/DevelopmentModeTileTest.java b/tests/robotests/src/com/android/settings/qstile/DevelopmentModeTileTest.java new file mode 100644 index 00000000000..a30bd47ca2f --- /dev/null +++ b/tests/robotests/src/com/android/settings/qstile/DevelopmentModeTileTest.java @@ -0,0 +1,75 @@ +package com.android.settings.qstile; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Intent; +import android.service.quicksettings.Tile; + +import com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.TestConfig; +import com.android.settings.testutils.shadow.ShadowTileService; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; +import org.robolectric.annotation.Config; +import org.robolectric.internal.ShadowExtractor; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, + shadows = ShadowTileService.class) +public class DevelopmentModeTileTest { + + @Mock private Tile mTile; + @Mock private DevelopmentModeTile.DevModeProperties mProps; + + private DevelopmentModeTile mDevelopmentModeTile; + private ShadowTileService mShadowTileService; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mDevelopmentModeTile = Robolectric.buildService(DevelopmentModeTile.class).get(); + + ReflectionHelpers.setField(mDevelopmentModeTile, "mProps", mProps); + mShadowTileService = (ShadowTileService) ShadowExtractor.extract(mDevelopmentModeTile); + mShadowTileService.setTile(mTile); + } + + @Test + public void refresh() { + verifyRefreshState(false, true, Tile.STATE_UNAVAILABLE); + verifyRefreshState(false, false, Tile.STATE_UNAVAILABLE); + verifyRefreshState(true, false, Tile.STATE_INACTIVE); + verifyRefreshState(true, true, Tile.STATE_ACTIVE); + } + + @Test + public void onClick_startSetting() { + when(mTile.getState()).thenReturn(Tile.STATE_UNAVAILABLE); + mDevelopmentModeTile.onClick(); + + Intent intent = mShadowTileService.getNextStartedActivity(); + assertEquals(DevelopmentTileConfigActivity.class.getName(), + intent.getComponent().getClassName()); + } + + private void verifyRefreshState(boolean isSet, boolean allMatch, int expectedState) { + reset(mProps, mTile); + + mProps.isSet = isSet; + mProps.allMatch = allMatch; + mDevelopmentModeTile.refresh(); + + verify(mProps).refreshState(eq(mDevelopmentModeTile)); + verify(mTile).setState(eq(expectedState)); + } +} diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowTileService.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowTileService.java new file mode 100644 index 00000000000..2270ff33834 --- /dev/null +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowTileService.java @@ -0,0 +1,38 @@ +package com.android.settings.testutils.shadow; + +import android.content.Intent; +import android.service.quicksettings.Tile; +import android.service.quicksettings.TileService; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.annotation.RealObject; +import org.robolectric.shadows.ShadowService; + +/** + * Shadow for {@link TileService}. + */ +@Implements(TileService.class) +public class ShadowTileService extends ShadowService { + + @RealObject TileService realService; + + private Tile mTile; + + public void __constructor__() { } + + @Implementation + public final Tile getQsTile() { + return mTile; + } + + @Implementation + public final void startActivityAndCollapse(Intent intent) { + realService.startActivity(intent); + } + + // Non-Android setter. + public void setTile(Tile tile) { + mTile = tile; + } +}