Removing one all-purpose developer tile and replacing it with 4 separate tiles,

for individual actions. Also adding a section in Developer Options for enabling
these individual tiles.

Bug: 34813634
Bug: 34909670
Test: Manually tested on device
Change-Id: I3adf5498f8b72959cb68cd508c44d87f953e450a
This commit is contained in:
Sunny Goyal
2017-02-06 15:19:00 -08:00
parent 17f16f6b98
commit c960751e0a
14 changed files with 423 additions and 504 deletions

View File

@@ -3420,11 +3420,41 @@
<!-- Quick Settings tiles for Developer Options -->
<service
android:name=".qstile.DevelopmentModeTile"
android:label="@string/developer_tile"
android:icon="@drawable/ic_settings_development"
android:name=".qstile.DevelopmentTiles$ShowLayout"
android:label="@string/debug_layout"
android:icon="@drawable/tile_icon_show_layout"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="true">
android:enabled="false">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
<service
android:name=".qstile.DevelopmentTiles$GPUProfiling"
android:label="@string/track_frame_time"
android:icon="@drawable/tile_icon_graphics"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
<service
android:name=".qstile.DevelopmentTiles$ForceRTL"
android:label="@string/force_rtl_layout_all_locales"
android:icon="@drawable/tile_icon_force_rtl"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
<service
android:name=".qstile.DevelopmentTiles$AnimationSpeed"
android:label="@string/window_animation_scale_title"
android:icon="@drawable/tile_icon_animation_speed"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
@@ -3433,11 +3463,7 @@
android:name=".qstile.DevelopmentTileConfigActivity"
android:excludeFromRecents="true"
android:launchMode="singleInstance"
android:label="@string/developer_tile">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
</intent-filter>
</activity>
android:label="@string/quick_settings_developer_tiles" />
<activity android:name=".HelpTrampoline"
android:exported="true"

View File

@@ -0,0 +1,25 @@
<!--
Copyright (C) 2017 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M4,2C2.89,2 2,2.89 2,4V14H4V4H14V2H4M8,6C6.89,6 6,6.89 6,8V18H8V8H18V6H8M12,10C10.89,10 10,10.89 10,12V20C10,21.11 10.89,22 12,22H20C21.11,22 22,21.11 22,20V12C22,10.89 21.11,10 20,10H12Z" />
</vector>

View File

@@ -0,0 +1,61 @@
<!--
Copyright (C) 2017 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M7,12L12,7V10H16V14H12V17L7,12" />
<path
android:fillColor="#80FFFFFF"
android:pathData="M0.0,6.0h1.0v12.0h-1.0z"/>
<path
android:fillColor="#80FFFFFF"
android:pathData="M6.0,0.0h12.0v1.0h-12.0z"/>
<path
android:fillColor="#80FFFFFF"
android:pathData="M23.0,6.0h1.0v12.0h-1.0z"/>
<path
android:fillColor="#80FFFFFF"
android:pathData="M6.0,23.0h12.0v1.0h-12.0z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M1.0,23.0l0.0,-5.0l-1.0,0.0l0.0,6.0l6.0,0.0l0.0,-1.0z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M1.0,1.0l5.0,0.0l0.0,-1.0l-6.0,0.0l0.0,6.0l1.0,0.0z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M18.0,0.0l0.0,1.0l5.0,0.0l0.0,5.0l1.0,0.0l0.0,-6.0z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M23.0,23.0l-5.0,0.0l0.0,1.0l6.0,0.0l0.0,-6.0l-1.0,0.0z"/>
<path
android:fillColor="#80FFFFFF"
android:pathData="M9.5,4h5.0v1.0h-5.0z"/>
<path
android:fillColor="#80FFFFFF"
android:pathData="M9.5,19h5.0v1.0h-5.0z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M4.5,5.0l5.0,0.0l0.0,-1.0l-6.0,0.0l0.0,10.0l0.0,6.0l6.0,0.0l0.0,-1.0l-5.0,0.0z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M14.5,4.0l0.0,1.0l5.0,0.0l0.0,14l-5.0,0.0l0.0,1.0l6.0,0.0l0.0,-16z"/>
</vector>

View File

@@ -0,0 +1,53 @@
<!--
Copyright (C) 2015 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M23,1v22H1V1H23 M24,0H0v24h24V0L24,0z"/>
<path
android:strokeColor="#FFFFFFFF"
android:strokeWidth="0.667"
android:pathData="M5,19L1,23"/>
<path
android:strokeColor="#FFFFFFFF"
android:strokeWidth="0.667"
android:pathData="M1,1L5,5"/>
<path
android:strokeColor="#FFFFFFFF"
android:strokeWidth="0.667"
android:pathData="M19,5L23,1"/>
<path
android:strokeColor="#FFFFFFFF"
android:strokeWidth="0.667"
android:pathData="M19,19L23,23"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M14,3.8l-4,0l-0.2,-0.8l4.4,0z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M18.8,5.2v13.5H5.2V5.2H18.8 M19.5,4.5h-15v15h15V4.5L19.5,4.5z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M6.5,9.5h5v11h-5z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M12.5,16.5h5v5h-5z"/>
</vector>

View File

@@ -0,0 +1,61 @@
<!--
Copyright (C) 2015 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M12,7.2c-3.2,0 -5.9,2 -7,4.8c1.1,2.8 3.8,4.8 7,4.8s5.9,-2 7,-4.8C17.9,9.2 15.2,7.2 12,7.2zM12,15.2c-1.8,0 -3.2,-1.4 -3.2,-3.2s1.4,-3.2 3.2,-3.2s3.2,1.4 3.2,3.2S13.8,15.2 12,15.2zM12,10.1c-1.1,0 -1.9,0.9 -1.9,1.9s0.9,1.9 1.9,1.9s1.9,-0.9 1.9,-1.9S13.1,10.1 12,10.1z"/>
<path
android:fillColor="#80FFFFFF"
android:pathData="M0.0,6.0h1.0v12.0h-1.0z"/>
<path
android:fillColor="#80FFFFFF"
android:pathData="M6.0,0.0h12.0v1.0h-12.0z"/>
<path
android:fillColor="#80FFFFFF"
android:pathData="M23.0,6.0h1.0v12.0h-1.0z"/>
<path
android:fillColor="#80FFFFFF"
android:pathData="M6.0,23.0h12.0v1.0h-12.0z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M1.0,23.0l0.0,-5.0l-1.0,0.0l0.0,6.0l6.0,0.0l0.0,-1.0z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M1.0,1.0l5.0,0.0l0.0,-1.0l-6.0,0.0l0.0,6.0l1.0,0.0z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M18.0,0.0l0.0,1.0l5.0,0.0l0.0,5.0l1.0,0.0l0.0,-6.0z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M23.0,23.0l-5.0,0.0l0.0,1.0l6.0,0.0l0.0,-6.0l-1.0,0.0z"/>
<path
android:fillColor="#80FFFFFF"
android:pathData="M9.5,6.0h5.0v1.0h-5.0z"/>
<path
android:fillColor="#80FFFFFF"
android:pathData="M9.5,17.0h5.0v1.0h-5.0z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M4.5,7.0l5.0,0.0l0.0,-1.0l-6.0,0.0l0.0,6.0l0.0,6.0l6.0,0.0l0.0,-1.0l-5.0,0.0l0.0,-5.0z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M14.5,6.0l0.0,1.0l5.0,0.0l0.0,5.0l0.0,5.0l-5.0,0.0l0.0,1.0l6.0,0.0l0.0,-6.0l0.0,-6.0z"/>
</vector>

View File

@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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
-->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:background="@drawable/switchbar_background"
android:text="@string/developer_tile_unavailable"
android:paddingStart="8dip"
android:paddingEnd="8dip"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit ="marquee_forever"
android:textSize="16sp"
android:fontFamily="sans-serif"
android:textColor="?android:attr/textColorPrimary"
android:gravity="center" />

View File

@@ -7757,12 +7757,6 @@
<!-- Title of developer options to set the smallest width of the screen [CHAR LIMIT=60]-->
<string name="developer_smallest_width">Smallest width</string>
<!-- Title of developer options time [CHAR LIMIT=60]-->
<string name="developer_tile">Development mode</string>
<!-- Message shown when there is no active state for development mode [CHAR LIMIT=NONE]-->
<string name="developer_tile_unavailable">No active state selected</string>
<!-- Message shown when there are no premium SMS apps [CHAR LIMIT=NONE] -->
<string name="premium_sms_none">No installed apps have requested Premium SMS access</string>
@@ -7778,6 +7772,9 @@
<!-- [CHAR LIMIT=60] Name of dev option called "System UI demo mode" -->
<string name="demo_mode">System UI demo mode</string>
<!-- [CHAR LIMIT=60] Name of dev option to enable extra quick settings tiles -->
<string name="quick_settings_developer_tiles">Quick settings developer tiles</string>
<!-- Title text for connecting to customer support [CHAR LIMIT=80]-->
<string name="support_escalation_title">We\'re here to help</string>

View File

@@ -102,6 +102,14 @@
<intent android:action="com.android.settings.action.DEMO_MODE" />
</Preference>
<Preference
android:key="quick_settings_tiles"
android:title="@string/quick_settings_developer_tiles">
<intent
android:targetPackage="com.android.settings"
android:targetClass="com.android.settings.qstile.DevelopmentTileConfigActivity" />
</Preference>
<PreferenceCategory android:key="debug_debugging_category"
android:title="@string/debug_debugging_category">

View File

@@ -1,114 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2017 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
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory
android:key="debug_input_category"
android:title="@string/debug_input_category">
<SwitchPreference
android:key="show_touches"
android:title="@string/show_touches"
android:summary="@string/show_touches_summary"/>
<SwitchPreference
android:key="pointer_location"
android:title="@string/pointer_location"
android:summary="@string/pointer_location_summary"/>
</PreferenceCategory>
<PreferenceCategory
android:key="debug_drawing_category"
android:title="@string/debug_drawing_category">
<SwitchPreference
android:key="debug_layout"
android:title="@string/debug_layout"
android:summary="@string/debug_layout_summary"/>
<SwitchPreference
android:key="force_rtl_layout_all_locales"
android:title="@string/force_rtl_layout_all_locales"
android:summary="@string/force_rtl_layout_all_locales_summary"/>
<ListPreference
android:key="window_animation_scale"
android:defaultValue="1"
android:summary="%s"
android:title="@string/window_animation_scale_title"
android:entries="@array/window_animation_scale_entries"
android:entryValues="@array/window_animation_scale_values" />
<ListPreference
android:key="transition_animation_scale"
android:defaultValue="1"
android:summary="%s"
android:title="@string/transition_animation_scale_title"
android:entries="@array/transition_animation_scale_entries"
android:entryValues="@array/transition_animation_scale_values" />
<ListPreference
android:key="animator_duration_scale"
android:defaultValue="1"
android:summary="%s"
android:title="@string/animator_duration_scale_title"
android:entries="@array/animator_duration_scale_entries"
android:entryValues="@array/animator_duration_scale_values" />
</PreferenceCategory>
<PreferenceCategory
android:key="debug_hw_drawing_category"
android:title="@string/debug_hw_drawing_category">
<SwitchPreference
android:key="show_hw_screen_udpates"
android:title="@string/show_hw_screen_updates"
android:summary="@string/show_hw_screen_updates_summary"/>
<SwitchPreference
android:key="show_hw_layers_udpates"
android:title="@string/show_hw_layers_updates"
android:summary="@string/show_hw_layers_updates_summary"/>
<ListPreference
android:key="debug_hw_overdraw"
android:defaultValue="false"
android:summary="%s"
android:title="@string/debug_hw_overdraw"
android:entries="@array/debug_hw_overdraw_entries"
android:entryValues="@array/debug_hw_overdraw_values" />
</PreferenceCategory>
<PreferenceCategory
android:key="debug_monitoring_category"
android:title="@string/debug_monitoring_category">
<ListPreference
android:key="track_frame_time"
android:defaultValue="false"
android:summary="%s"
android:title="@string/track_frame_time"
android:entries="@array/track_frame_time_entries"
android:entryValues="@array/track_frame_time_values" />
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -62,7 +62,6 @@ 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.DevelopmentModeTile;
import com.android.settings.search.DynamicIndexableContentMonitor;
import com.android.settings.search2.SearchFeatureProvider;
import com.android.settings.widget.SwitchBar;
@@ -941,9 +940,6 @@ public class SettingsActivity extends SettingsDrawerActivity
Settings.DevelopmentSettingsActivity.DASHBOARD_ALIAS),
showDev, isAdmin);
// Reveal development-only quick settings tiles
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).
List<DashboardCategory> categories;

View File

@@ -1,205 +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.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<String, ?> 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<String, ?> 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");
}
}
}

View File

@@ -16,16 +16,20 @@
package com.android.settings.qstile;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.view.View;
import android.service.quicksettings.TileService;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
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 {
@@ -42,35 +46,38 @@ public class DevelopmentTileConfigActivity extends SettingsActivity {
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;
public static class DevelopmentTileConfigFragment extends SettingsPreferenceFragment
implements Preference.OnPreferenceChangeListener {
@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();
}
Context context = getPrefContext();
setPreferenceScreen(getPreferenceManager().createPreferenceScreen(context));
getPreferenceScreen().removeAll();
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mSwitchBar = ((SettingsActivity) getActivity()).getSwitchBar();
mSwitchBar.setEnabled(false);
Intent intent = new Intent(TileService.ACTION_QS_TILE)
.setPackage(context.getPackageName());
PackageManager pm = getPackageManager();
for (ResolveInfo info :
pm.queryIntentServices(intent, PackageManager.MATCH_DISABLED_COMPONENTS)) {
ServiceInfo sInfo = info.serviceInfo;
int enabledSetting = pm.getComponentEnabledSetting(
new ComponentName(sInfo.packageName, sInfo.name));
boolean checked = enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|| ((enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)
&& sInfo.enabled);
SwitchPreference preference = new SwitchPreference(context);
preference.setTitle(sInfo.loadLabel(pm));
preference.setIcon(sInfo.icon);
preference.setKey(sInfo.name);
preference.setChecked(checked);
preference.setPersistent(false);
preference.setOnPreferenceChangeListener(this);
getPreferenceScreen().addPreference(preference);
}
}
@Override
@@ -79,37 +86,14 @@ public class DevelopmentTileConfigActivity extends SettingsActivity {
}
@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);
}
public boolean onPreferenceChange(Preference preference, Object newValue) {
ComponentName cn = new ComponentName(
getPrefContext().getPackageName(), preference.getKey());
getPackageManager().setComponentEnabledSetting(cn, (Boolean) newValue
? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
return true;
}
}
}
}

View File

@@ -0,0 +1,134 @@
/*
* 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.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;
public abstract class DevelopmentTiles extends TileService {
protected abstract boolean isEnabled();
protected abstract void setIsEnabled(boolean isEnabled);
@Override
public void onStartListening() {
super.onStartListening();
refresh();
}
public void refresh() {
getQsTile().setState(isEnabled() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
getQsTile().updateTile();
}
@Override
public void onClick() {
setIsEnabled(getQsTile().getState() == Tile.STATE_INACTIVE);
new DevelopmentSettings.SystemPropPoker().execute(); // Settings app magic
refresh();
}
/**
* Tile to control the "Show layout bounds" developer setting
*/
public static class ShowLayout extends DevelopmentTiles {
@Override
protected boolean isEnabled() {
return SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
}
@Override
protected void setIsEnabled(boolean isEnabled) {
SystemProperties.set(View.DEBUG_LAYOUT_PROPERTY, isEnabled ? "true" : "false");
}
}
/**
* Tile to control the "GPU profiling" developer setting
*/
public static class GPUProfiling extends DevelopmentTiles {
@Override
protected boolean isEnabled() {
final String value = SystemProperties.get(ThreadedRenderer.PROFILE_PROPERTY);
return value.equals("visual_bars");
}
@Override
protected void setIsEnabled(boolean isEnabled) {
SystemProperties.set(ThreadedRenderer.PROFILE_PROPERTY, isEnabled ? "visual_bars" : "");
}
}
/**
* Tile to control the "Force RTL" developer setting
*/
public static class ForceRTL extends DevelopmentTiles {
@Override
protected boolean isEnabled() {
return Settings.Global.getInt(
getContentResolver(), Settings.Global.DEVELOPMENT_FORCE_RTL, 0) != 0;
}
@Override
protected void setIsEnabled(boolean isEnabled) {
Settings.Global.putInt(
getContentResolver(), Settings.Global.DEVELOPMENT_FORCE_RTL, isEnabled ? 1 : 0);
SystemProperties.set(Settings.Global.DEVELOPMENT_FORCE_RTL, isEnabled ? "1" : "0");
LocalePicker.updateLocales(getResources().getConfiguration().getLocales());
}
}
/**
* Tile to control the "Animation speed" developer setting
*/
public static class AnimationSpeed extends DevelopmentTiles {
@Override
protected boolean isEnabled() {
IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
try {
return wm.getAnimationScale(0) != 1;
} catch (RemoteException e) { }
return false;
}
@Override
protected void setIsEnabled(boolean isEnabled) {
IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
float scale = isEnabled ? 10 : 1;
try {
wm.setAnimationScale(0, scale);
wm.setAnimationScale(1, scale);
wm.setAnimationScale(2, scale);
} catch (RemoteException e) { }
}
}
}

View File

@@ -1,75 +0,0 @@
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));
}
}