Merge "Clarify secondary dnd media text."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8eaf761..0418d51 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2573,7 +2573,7 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.applications.PictureInPictureSettings" />
+ android:value="com.android.settings.applications.appinfo.PictureInPictureSettings" />
</activity>
<activity android:name="Settings$AppPictureInPictureSettingsActivity"
@@ -2585,7 +2585,7 @@
<data android:scheme="package" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.applications.PictureInPictureDetails" />
+ android:value="com.android.settings.applications.appinfo.PictureInPictureDetails" />
</activity>
<activity android:name="Settings$ZenAccessSettingsActivity"
@@ -2939,7 +2939,7 @@
<data android:scheme="package" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.applications.DrawOverlayDetails" />
+ android:value="com.android.settings.applications.appinfo.DrawOverlayDetails" />
</activity>
<activity android:name="Settings$WriteSettingsActivity"
@@ -2963,7 +2963,7 @@
<data android:scheme="package" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.applications.WriteSettingsDetails" />
+ android:value="com.android.settings.applications.appinfo.WriteSettingsDetails" />
</activity>
<activity android:name="Settings$ManageExternalSourcesActivity"
@@ -2986,7 +2986,7 @@
<data android:scheme="package" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.applications.ExternalSourcesDetails" />
+ android:value="com.android.settings.applications.appinfo.ExternalSourcesDetails" />
</activity>
<activity android:name="ShowAdminSupportDetailsDialog"
@@ -3312,13 +3312,13 @@
</intent-filter>
</activity>
- <provider android:name=".SettingsSliceProvider"
+ <provider android:name=".slices.SettingsSliceProvider"
android:authorities="com.android.settings.slices"
android:exported="true">
</provider>
<receiver
- android:name=".SliceBroadcastReceiver" >
+ android:name=".slices.SliceBroadcastReceiver" >
<intent-filter>
<action android:name="com.android.settings.slice.action.WIFI_CHANGED"/>
</intent-filter>
diff --git a/color-check-baseline.xml b/color-check-baseline.xml
index cbcdf48..6fa2042 100644
--- a/color-check-baseline.xml
+++ b/color-check-baseline.xml
@@ -2,6 +2,18 @@
<issues format="4">
<issue
+ id="LintError"
+ severity="Error"
+ message="No `.class` files were found in project ".", so none of the classfile based checks could be run. Does the project need to be built first?"
+ category="Lint"
+ priority="10"
+ summary="Lint Failure"
+ explanation="This issue type represents a problem running lint itself. Examples include failure to find bytecode for source files (which means certain detectors could not be run), parsing errors in lint configuration files, etc.
These errors are not errors in your own code, but they are shown to make it clear that some checks were not completed.">
+ <location
+ file="."/>
+ </issue>
+
+ <issue
id="HardCodedColor"
severity="Error"
message="Avoid using hardcoded color"
@@ -93,7 +105,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/layout-land/choose_lock_pattern.xml"
- line="152"
+ line="160"
column="17"/>
</issue>
@@ -1085,7 +1097,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/layout-land/confirm_lock_pattern_internal.xml"
- line="110"
+ line="111"
column="17"/>
</issue>
@@ -1289,6 +1301,134 @@
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item android:color="#19263238" android:offset="0.0"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/ic_color_inversion.xml"
+ line="17"
+ column="23"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item android:color="#00212121" android:offset="1.0"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/ic_color_inversion.xml"
+ line="18"
+ column="23"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item android:color="#19FFFFFF" android:offset="0.0"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/ic_color_inversion.xml"
+ line="32"
+ column="23"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item android:color="#00FFFFFF" android:offset="1.0"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/ic_color_inversion.xml"
+ line="33"
+ column="23"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item android:color="#19263238" android:offset="0.0"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/ic_daltonizer.xml"
+ line="16"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item android:color="#00212121" android:offset="1.0"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/ic_daltonizer.xml"
+ line="17"
+ column="27"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item android:color="#19FFFFFF" android:offset="0.0"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/ic_daltonizer.xml"
+ line="36"
+ column="23"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
+ errorLine1=" <item android:color="#00FFFFFF" android:offset="1.0"/>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="res/drawable/ic_daltonizer.xml"
+ line="37"
+ column="23"/>
+ </issue>
+
+ <issue
+ id="HardCodedColor"
+ severity="Error"
+ message="Avoid using hardcoded color"
+ category="Correctness"
+ priority="4"
+ summary="Using hardcoded color"
+ explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" android:tint="@color/wifi_details_icon_color">"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
@@ -1869,7 +2009,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/layout/settings_main_dashboard.xml"
- line="29"
+ line="30"
column="9"/>
</issue>
@@ -1933,7 +2073,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-en-rXC/strings.xml"
- line="2335"
+ line="2333"
column="168"/>
</issue>
@@ -1949,7 +2089,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-en-rAU/strings.xml"
- line="2341"
+ line="2334"
column="64"/>
</issue>
@@ -1965,7 +2105,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-en-rCA/strings.xml"
- line="2341"
+ line="2334"
column="64"/>
</issue>
@@ -1981,7 +2121,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-en-rGB/strings.xml"
- line="2341"
+ line="2334"
column="64"/>
</issue>
@@ -1997,7 +2137,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-en-rIN/strings.xml"
- line="2341"
+ line="2334"
column="64"/>
</issue>
@@ -2013,7 +2153,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/strings.xml"
- line="5501"
+ line="5512"
column="36"/>
</issue>
@@ -2029,7 +2169,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="245"
+ line="246"
column="41"/>
</issue>
@@ -2045,7 +2185,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="364"
+ line="366"
column="42"/>
</issue>
@@ -2061,7 +2201,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="441"
+ line="443"
column="44"/>
</issue>
@@ -2077,7 +2217,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="447"
+ line="449"
column="44"/>
</issue>
@@ -2093,7 +2233,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="448"
+ line="450"
column="44"/>
</issue>
@@ -2109,7 +2249,7 @@
errorLine2=" ^">
<location
file="res/values/styles.xml"
- line="471"
+ line="473"
column="41"/>
</issue>
diff --git a/res/drawable/ic_color_inversion.xml b/res/drawable/ic_color_inversion.xml
new file mode 100644
index 0000000..aa59f5a
--- /dev/null
+++ b/res/drawable/ic_color_inversion.xml
@@ -0,0 +1,52 @@
+<!--
+ Copyright 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 android:height="192dp" android:viewportHeight="192.0"
+ android:viewportWidth="192.0" android:width="192dp"
+ xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#546E7A" android:pathData="M37.2,173.6l-28.5,-90c-1.7,-5.8 0.3,-12 5,-15.6l73.6,-57.1c5.2,-4 12.5,-4 17.6,0.1L178.6,70c4.6,3.7 6.5,9.9 4.8,15.6l-28.5,88.2c-1.9,6.1 -7.4,10.2 -13.7,10.2H50.8C44.5,183.9 39,179.7 37.2,173.6z"/>
+ <path android:fillAlpha="0.2" android:fillColor="#263238"
+ android:pathData="M183.3,84.5l-28.5,88.2c-1.8,6.1 -7.4,10.2 -13.7,10.2H50.9c-6.3,0 -11.9,-4.2 -13.7,-10.3l-28.5,-90C8.2,81.4 8,80.1 8,78.9c-0.1,1.6 0.1,3.1 0.6,4.7l28.5,90c1.8,6.1 7.4,10.3 13.7,10.3h90.3c6.3,0 11.8,-4.1 13.7,-10.2l28.5,-88.2c0.5,-1.6 0.7,-3.2 0.6,-4.7C183.9,82 183.7,83.3 183.3,84.5z" android:strokeAlpha="0.2"/>
+ <path android:fillAlpha="0.2" android:fillColor="#FFFFFF"
+ android:pathData="M13.6,69l73.6,-57.1c5.2,-4 12.5,-4 17.6,0.1l73.8,58.9c3.4,2.7 5.3,6.7 5.4,10.8c0.2,-4.5 -1.8,-8.9 -5.4,-11.8L104.8,11c-5.2,-4.1 -12.4,-4.1 -17.6,-0.1L13.5,68C9.8,70.9 7.8,75.4 8,80C8.1,75.8 10.1,71.7 13.6,69z" android:strokeAlpha="0.2"/>
+ <path android:fillAlpha="0.2" android:fillColor="#FFFFFF"
+ android:pathData="M53.1,129.9l5,-4.8l-13.9,-13.3c0,0.8 -0.1,1.5 -0.2,2.3c-0.4,22.3 17.2,40.2 39.9,41.7l0.1,-5.3C70.2,149.5 58.6,141.4 53.1,129.9z" android:strokeAlpha="0.2"/>
+ <path android:fillAlpha="0.2" android:fillColor="#FFFFFF"
+ android:pathData="M108.7,51.8l-0.1,5.3c13.6,1 25,9.2 30.4,20.7l-4.9,4.8l13.6,13.3c0.1,-0.8 0.2,-1.5 0.2,-2.3C148.3,71.2 131,53.2 108.7,51.8z" android:strokeAlpha="0.2"/>
+ <path android:pathData="M154.9,173.7l13.7,-41.7l-49.5,-49.6l-18.6,-7.2l-19.6,3.1L65.9,98.6L74,128l55.9,55.9h11.2C147.5,183.9 153.1,179.8 154.9,173.7z">
+ <aapt:attr name="android:fillColor">
+ <gradient android:endX="139.008" android:endY="147.6131"
+ android:startX="98.1033" android:startY="106.7084" android:type="linear">
+ <item android:color="#19263238" android:offset="0.0"/>
+ <item android:color="#00212121" android:offset="1.0"/>
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path android:fillAlpha="0.1" android:fillColor="#FF000000"
+ android:pathData="M70.3,104.5c0,0.2 0,0.3 0,0.5c0.3,-13.9 11.6,-25.1 25.6,-25.1v-1C81.8,78.9 70.3,90.4 70.3,104.5z" android:strokeAlpha="0.1"/>
+ <path android:fillAlpha="0.1" android:fillColor="#FF000000"
+ android:pathData="M95.9,136.5c-17.5,0 -31.7,-14 -32,-31.5c0,0.2 0,0.3 0,0.5c0,17.7 14.3,32 32,32c17.7,0 32,-14.3 32,-32c0,-0.2 0,-0.3 0,-0.5C127.6,122.5 113.4,136.5 95.9,136.5z" android:strokeAlpha="0.1"/>
+ <path android:fillColor="#FFFFFF" android:pathData="M95.9,72.5c-17.7,0 -32,14.3 -32,32c0,17.7 14.3,32 32,32c17.7,0 32,-14.3 32,-32S113.6,72.5 95.9,72.5zM70.3,104.5c0,-14.1 11.5,-25.6 25.6,-25.6v51.2C81.8,130.1 70.3,118.6 70.3,104.5z"/>
+ <path android:pathData="M37.1,173.6l-28.5,-90c-1.7,-5.8 0.3,-12 5,-15.6l73.5,-57.1c5.2,-4 12.5,-4 17.6,0.1l73.8,58.9c4.6,3.7 6.5,9.9 4.8,15.6l-28.5,88.2c-1.8,6.1 -7.4,10.2 -13.7,10.2H50.8C44.5,183.9 38.9,179.7 37.1,173.6z">
+ <aapt:attr name="android:fillColor">
+ <gradient android:centerX="21.9873"
+ android:centerY="23.7751"
+ android:gradientRadius="158.0384" android:type="radial">
+ <item android:color="#19FFFFFF" android:offset="0.0"/>
+ <item android:color="#00FFFFFF" android:offset="1.0"/>
+ </gradient>
+ </aapt:attr>
+ </path>
+</vector>
diff --git a/res/drawable/ic_daltonizer.xml b/res/drawable/ic_daltonizer.xml
new file mode 100644
index 0000000..04e397d
--- /dev/null
+++ b/res/drawable/ic_daltonizer.xml
@@ -0,0 +1,56 @@
+<!--
+ Copyright 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 android:height="192dp" android:viewportHeight="192.0"
+ android:viewportWidth="192.0" android:width="192dp"
+ xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#00BCD4" android:pathData="M37.1,173.5l-28.5,-90c-1.7,-5.8 0.3,-12 5,-15.6l73.6,-57.1c5.2,-4 12.5,-4 17.6,0.1l73.8,58.9c4.6,3.7 6.5,9.9 4.8,15.6l-28.5,88.2c-1.9,6.1 -7.4,10.2 -13.7,10.2H50.8C44.5,183.8 39,179.6 37.1,173.5z"/>
+ <path android:fillAlpha="0.2" android:fillColor="#263238"
+ android:pathData="M183.3,84.3l-28.5,88.2c-1.8,6.1 -7.4,10.2 -13.7,10.2H50.8c-6.3,0 -11.9,-4.2 -13.7,-10.3l-28.5,-90C8.2,81.2 8,79.9 8,78.7c-0.1,1.6 0.1,3.1 0.6,4.7l28.5,90c1.8,6.1 7.4,10.3 13.7,10.3h90.3c6.3,0 11.8,-4.1 13.7,-10.2l28.5,-88.2c0.5,-1.6 0.7,-3.2 0.6,-4.7C183.9,81.8 183.7,83.2 183.3,84.3z" android:strokeAlpha="0.2"/>
+ <path android:fillAlpha="0.2" android:fillColor="#FFFFFF"
+ android:pathData="M13.5,68.8l73.6,-57.1c5.2,-4 12.5,-4 17.6,0.1l73.8,58.9c3.4,2.7 5.3,6.7 5.4,10.8c0.2,-4.5 -1.8,-8.9 -5.4,-11.8l-73.8,-58.9c-5.2,-4.1 -12.4,-4.1 -17.6,-0.1L13.5,67.8c-3.7,2.9 -5.7,7.4 -5.5,12C8.1,75.6 10.1,71.5 13.5,68.8z" android:strokeAlpha="0.2"/>
+ <group>
+ <clip-path android:pathData="M37.1,173.5l-28.5,-90c-1.7,-5.8 0.3,-12 5,-15.6l73.6,-57.1c5.2,-4 12.5,-4 17.6,0.1l73.8,58.9c4.6,3.7 6.5,9.9 4.8,15.6l-28.5,88.2c-1.9,6.1 -7.4,10.2 -13.7,10.2H50.8C44.5,183.8 39,179.6 37.1,173.5z M 0,0"/>
+ <path android:pathData="M131.3,74.7L105,79.3l-5,-0.2l-3.8,2.4l-30.8,34.4L60.5,136l47.8,47.8 h32.9c6.3,0,11.8,-4.1,13.7,-10.2l18.4,-56.9L131.3,74.7z">
+ <aapt:attr name="android:fillColor">
+ <gradient android:endX="151.1709"
+ android:endY="160.5809" android:startX="91.7117"
+ android:startY="101.1217" android:type="linear">
+ <item android:color="#19263238" android:offset="0.0"/>
+ <item android:color="#00212121" android:offset="1.0"/>
+ </gradient>
+ </aapt:attr>
+ </path>
+ </group>
+ <path android:fillAlpha="0.1" android:fillColor="#263238"
+ android:pathData="M79.5,136l-18.9,0l1,1l18.9,0l35.6,-35.6l-1,-1z" android:strokeAlpha="0.1"/>
+ <path android:fillAlpha="0.1" android:fillColor="#263238"
+ android:pathData="M68.59,120.37l32.17,-32.17l0.99,0.99l-32.17,32.17z" android:strokeAlpha="0.1"/>
+ <path android:fillAlpha="0.1" android:fillColor="#263238"
+ android:pathData="M132.3,75.6l-1,-1c1.6,1.6 1.6,4.1 0,5.7l-12.4,12.4l1,1l12.4,-12.4C133.8,79.7 133.8,77.2 132.3,75.6z" android:strokeAlpha="0.1"/>
+ <path android:fillAlpha="0.1" android:fillColor="#263238"
+ android:pathData="M120.75,106.06l5.66,-5.66l0.99,0.99l-5.66,5.66z" android:strokeAlpha="0.1"/>
+ <path android:fillColor="#0097A7" android:pathData="M68.56,120.37l32.17,-32.17l7.64,7.64l-32.17,32.17z"/>
+ <path android:fillColor="#FFFFFF" android:pathData="M131.3,74.6l-9.3,-9.3c-1.6,-1.6 -4.1,-1.6 -5.6,0l-12.4,12.4l-7.7,-7.6l-5.6,5.6l5.7,5.7L60.6,117v19h19l35.6,-35.6l5.7,5.7l5.6,-5.6l-7.7,-7.7l12.4,-12.4C132.8,78.7 132.8,76.2 131.3,74.6zM76.2,128l-7.7,-7.7l32.2,-32.2l7.7,7.7L76.2,128z"/>
+ <path android:pathData="M37.1,173.5l-28.5,-90c-1.7,-5.8 0.3,-12 5,-15.6l73.5,-57.1c5.2,-4 12.5,-4 17.6,0.1l73.8,58.9c4.6,3.7 6.5,9.9 4.8,15.6l-28.5,88.2c-1.8,6.1 -7.4,10.2 -13.7,10.2H50.8C44.5,183.8 38.9,179.6 37.1,173.5z">
+ <aapt:attr name="android:fillColor">
+ <gradient android:centerX="21.977" android:centerY="23.6809"
+ android:gradientRadius="158.0384" android:type="radial">
+ <item android:color="#19FFFFFF" android:offset="0.0"/>
+ <item android:color="#00FFFFFF" android:offset="1.0"/>
+ </gradient>
+ </aapt:attr>
+ </path>
+</vector>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 2ba7919..e3fa070 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -97,6 +97,7 @@
<!-- For Search -->
<declare-styleable name="Preference">
<attr name="keywords" format="string" />
+ <attr name="controller" format="string" />
</declare-styleable>
<!-- For DotsPageIndicator -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f73d7d9..694a1b0 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -393,6 +393,8 @@
<string name="bluetooth_paired_device_title">Your devices</string>
<!-- Title for pairing bluetooth device page [CHAR LIMIT=none] -->
<string name="bluetooth_pairing_page_title">Pair new device</string>
+ <!-- Summary for bluetooth item in connection detail page -->
+ <string name="bluetooth_pref_summary">Allow device to pair and connect to bluetooth devices</string>
<!-- Title for connected device group [CHAR LIMIT=none]-->
<string name="connected_device_connected_title">Currently connected</string>
@@ -9130,4 +9132,9 @@
<!-- Note displayed when certain features are not available on low ram devices. [CHAR LIMIT=NONE] -->
<string name="disabled_low_ram_device">This feature is not available on this device</string>
+ <!-- UI debug setting: enable gnss raw meas full tracking [CHAR LIMIT=25] -->
+ <string name="enable_gnss_raw_meas_full_tracking">Force Full GnssMeasurement</string>
+ <!-- UI debug setting: enable gpu debug layers summary [CHAR LIMIT=50] -->
+ <string name="enable_gnss_raw_meas_full_tracking_summary">Disable GNSS duty-cycling, track all constellations and frequencies.</string>
+
</resources>
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index 7728a07..d7d2e02 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -118,12 +118,14 @@
<Preference
android:fragment="com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment"
android:key="daltonizer_preference_screen"
- android:title="@string/accessibility_display_daltonizer_preference_title" />
+ android:title="@string/accessibility_display_daltonizer_preference_title"
+ android:icon="@drawable/ic_daltonizer"/>
<SwitchPreference
android:key="toggle_inversion_preference"
android:title="@string/accessibility_display_inversion_preference_title"
android:summary="@string/accessibility_display_inversion_preference_subtitle"
- android:persistent="false" />
+ android:persistent="false"
+ android:icon="@drawable/ic_color_inversion"/>
</PreferenceCategory>
</PreferenceScreen>
diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml
index 664210b..99c76b8 100644
--- a/res/xml/app_info_settings.xml
+++ b/res/xml/app_info_settings.xml
@@ -132,6 +132,17 @@
</PreferenceCategory>
+ <!-- App installer info -->
+ <PreferenceCategory
+ android:key="app_installer"
+ android:title="@string/app_install_details_group_title">
+
+ <Preference
+ android:key="app_info_store"
+ android:title="@string/app_install_details_title" />
+
+ </PreferenceCategory>
+
<Preference
android:key="app_version"
android:selectable="false"
diff --git a/res/xml/bluetooth_pairing_detail.xml b/res/xml/bluetooth_pairing_detail.xml
index e60da75..e654a3c 100644
--- a/res/xml/bluetooth_pairing_detail.xml
+++ b/res/xml/bluetooth_pairing_detail.xml
@@ -19,7 +19,9 @@
android:title="@string/bluetooth_pairing_pref_title">
<Preference
- android:key="device_name"/>
+ android:key="bt_pair_rename_devices"
+ android:title="@string/bluetooth_device_name"
+ android:summary="@string/summary_placeholder" />
<com.android.settings.bluetooth.BluetoothProgressCategory
android:key="available_devices"
diff --git a/res/xml/connected_devices_advanced.xml b/res/xml/connected_devices_advanced.xml
index 946151f..57a2580 100644
--- a/res/xml/connected_devices_advanced.xml
+++ b/res/xml/connected_devices_advanced.xml
@@ -19,10 +19,11 @@
android:key="connected_devices_screen"
android:title="@string/connected_devices_dashboard_title">
- <com.android.settings.widget.MasterSwitchPreference
- android:key="toggle_bluetooth"
+ <SwitchPreference
+ android:key="toggle_bluetooth_switch"
android:title="@string/bluetooth_settings_title"
android:icon="@drawable/ic_settings_bluetooth"
+ android:summary="@string/bluetooth_pref_summary"
android:order="-7"/>
<SwitchPreference
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index d1eb366..60efcab 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -133,6 +133,11 @@
android:title="@string/mock_location_app" />
<SwitchPreference
+ android:key="enable_gnss_raw_meas_full_tracking"
+ android:title="@string/enable_gnss_raw_meas_full_tracking"
+ android:summary="@string/enable_gnss_raw_meas_full_tracking_summary"/>
+
+ <SwitchPreference
android:key="debug_view_attributes"
android:title="@string/debug_view_attributes" />
diff --git a/res/xml/device_info_settings.xml b/res/xml/device_info_settings.xml
deleted file mode 100644
index af1fb70..0000000
--- a/res/xml/device_info_settings.xml
+++ /dev/null
@@ -1,99 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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"
- android:key="device_info_pref_screen"
- android:title="@string/about_settings">
-
- <!-- Device status - launches activity -->
- <Preference android:key="status_info"
- android:title="@string/device_status"
- android:summary="@string/device_status_summary"
- android:fragment="com.android.settings.deviceinfo.Status"/>
-
- <!-- Manual -->
- <Preference
- android:key="manual"
- android:title="@string/manual">
- <intent android:action="android.settings.SHOW_MANUAL" />
- </Preference>
-
- <!-- Legal Information -->
- <Preference
- android:key="legal_container"
- android:title="@string/legal_information"
- android:fragment="com.android.settings.LegalSettings" />
-
- <Preference
- android:key="regulatory_info"
- android:title="@string/regulatory_labels">
- <intent android:action="android.settings.SHOW_REGULATORY_INFO" />
- </Preference>
-
- <Preference
- android:key="safety_info"
- android:title="@string/safety_and_regulatory_info">
- <intent android:action="android.settings.SHOW_SAFETY_AND_REGULATORY_INFO" />
- </Preference>
-
- <!-- Feedback on the device -->
- <Preference android:key="device_feedback"
- android:title="@string/device_feedback" />
-
- <!-- Device hardware model -->
- <Preference
- android:key="device_model"
- android:title="@string/model_info"
- android:summary="@string/summary_placeholder"/>
-
- <!-- Device firmware version -->
- <Preference android:key="firmware_version"
- android:title="@string/firmware_version"
- android:summary="@string/summary_placeholder"/>
-
- <!-- Security patch level -->
- <Preference android:key="security_patch"
- android:title="@string/security_patch"
- android:summary="@string/summary_placeholder">
- <intent android:action="android.intent.action.VIEW"
- android:data="https://source.android.com/security/bulletin/" />
- </Preference>
-
- <!-- Device FCC equipment id -->
- <Preference
- android:key="fcc_equipment_id"
- android:title="@string/fcc_equipment_id"
- android:summary="@string/summary_placeholder"/>
-
- <!-- Device Baseband version -->
- <Preference
- android:key="baseband_version"
- android:title="@string/baseband_version"
- android:summary="@string/summary_placeholder"/>
-
- <!-- Device Kernel version -->
- <Preference
- android:key="kernel_version"
- android:title="@string/kernel_version"
- android:summary="@string/summary_placeholder"/>
-
- <!-- Detailed build version -->
- <Preference
- android:key="build_number"
- android:title="@string/build_number"
- android:summary="@string/summary_placeholder"/>
-
-</PreferenceScreen>
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index f9f5d2b..333fd2a 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -25,8 +25,9 @@
<Preference
android:key="brightness"
android:title="@string/brightness"
- settings:keywords="@string/keywords_display_brightness_level">
- <intent android:action="com.android.intent.action.SHOW_BRIGHTNESS_DIALOG" />
+ settings:keywords="@string/keywords_display_brightness_level"
+ settings:controller="com.android.settings.display.AutoBrightnessPreferenceController">
+ <intent android:action="com.android.intent.action.SHOW_BRIGHTNESS_DIALOG" />
</Preference>
<com.android.settings.display.NightDisplayPreference
diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml
index 6adfc93..829bc53 100644
--- a/res/xml/special_access.xml
+++ b/res/xml/special_access.xml
@@ -68,7 +68,7 @@
<Preference
android:key="picture_in_picture"
android:title="@string/picture_in_picture_title"
- android:fragment="com.android.settings.applications.PictureInPictureSettings"
+ android:fragment="com.android.settings.applications.appinfo.PictureInPictureSettings"
settings:keywords="@string/picture_in_picture_keywords" />
<Preference
diff --git a/res/xml/system_dashboard_fragment.xml b/res/xml/system_dashboard_fragment.xml
index 8b9d0ca..1dfa6fb 100644
--- a/res/xml/system_dashboard_fragment.xml
+++ b/res/xml/system_dashboard_fragment.xml
@@ -26,7 +26,8 @@
android:title="@string/gesture_preference_title"
android:icon="@drawable/ic_settings_gestures"
android:order="-250"
- android:fragment="com.android.settings.gestures.GestureSettings" />
+ android:fragment="com.android.settings.gestures.GestureSettings"
+ settings:controller="com.android.settings.gestures.GesturesSettingPreferenceController"/>
<!-- Backup -->
<Preference
@@ -34,7 +35,8 @@
android:title="@string/privacy_settings_title"
android:summary="@string/summary_placeholder"
android:icon="@drawable/ic_settings_backup"
- android:order="-60">
+ android:order="-60"
+ settings:controller="com.android.settings.backup.BackupSettingsActivityPreferenceController">
<intent android:action="android.settings.BACKUP_AND_RESET_SETTINGS" />
</Preference>
@@ -44,14 +46,16 @@
android:title="@string/system_update_settings_list_item_title"
android:summary="@string/summary_placeholder"
android:icon="@drawable/ic_system_update"
- android:order="-30">
+ android:order="-30"
+ settings:controller="com.android.settings.deviceinfo.SystemUpdatePreferenceController">
<intent android:action="android.settings.SYSTEM_UPDATE_SETTINGS" />
</Preference>
<Preference
android:key="additional_system_update_settings"
android:title="@string/additional_system_update_settings_list_item_title"
- android:order="-31">
+ android:order="-31"
+ settings:controller="com.android.settings.deviceinfo.AdditionalSystemUpdatePreferenceController">
<intent android:action="android.intent.action.MAIN"
android:targetPackage="@string/additional_system_update"
android:targetClass="@string/additional_system_update_menu" />
diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java
index 2fd769b..0ad882d 100644
--- a/src/com/android/settings/DeviceAdminAdd.java
+++ b/src/com/android/settings/DeviceAdminAdd.java
@@ -69,6 +69,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
public class DeviceAdminAdd extends Activity {
static final String TAG = "DeviceAdminAdd";
@@ -145,18 +146,14 @@
DevicePolicyManager.EXTRA_DEVICE_ADMIN);
if (who == null) {
String packageName = getIntent().getStringExtra(EXTRA_DEVICE_ADMIN_PACKAGE_NAME);
- for (ComponentName component : mDPM.getActiveAdmins()) {
- if (component.getPackageName().equals(packageName)) {
- who = component;
- mUninstalling = true;
- break;
- }
- }
- if (who == null) {
+ Optional<ComponentName> installedAdmin = findAdminWithPackageName(packageName);
+ if (!installedAdmin.isPresent()) {
Log.w(TAG, "No component specified in " + action);
finish();
return;
}
+ who = installedAdmin.get();
+ mUninstalling = true;
}
if (action != null && action.equals(DevicePolicyManager.ACTION_SET_PROFILE_OWNER)) {
@@ -692,6 +689,18 @@
return info != null ? info.isManagedProfile() : false;
}
+ /**
+ * @return an {@link Optional} containing the admin with a given package name, if it exists,
+ * or {@link Optional#empty()} otherwise.
+ */
+ private Optional<ComponentName> findAdminWithPackageName(String packageName) {
+ List<ComponentName> admins = mDPM.getActiveAdmins();
+ if (admins == null) {
+ return Optional.empty();
+ }
+ return admins.stream().filter(i -> i.getPackageName().equals(packageName)).findAny();
+ }
+
private boolean isAdminUninstallable() {
// System apps can't be uninstalled.
return !mDeviceAdmin.getActivityInfo().applicationInfo.isSystemApp();
diff --git a/src/com/android/settings/DeviceInfoSettings.java b/src/com/android/settings/DeviceInfoSettings.java
index 74ce5d0..7e32e5e 100644
--- a/src/com/android/settings/DeviceInfoSettings.java
+++ b/src/com/android/settings/DeviceInfoSettings.java
@@ -16,36 +16,29 @@
package com.android.settings;
-import static com.android.settings.core.FeatureFlags.DEVICE_INFO_V2;
-
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.provider.SearchIndexableResource;
-import android.telephony.TelephonyManager;
-import android.util.FeatureFlagUtils;
import android.support.annotation.VisibleForTesting;
+import android.telephony.TelephonyManager;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.SummaryLoader;
-import com.android.settings.deviceinfo.BasebandVersionPreferenceController;
import com.android.settings.deviceinfo.BluetoothAddressPreferenceController;
import com.android.settings.deviceinfo.BuildNumberPreferenceController;
import com.android.settings.deviceinfo.DeviceModelPreferenceController;
import com.android.settings.deviceinfo.FccEquipmentIdPreferenceController;
import com.android.settings.deviceinfo.FeedbackPreferenceController;
-import com.android.settings.deviceinfo.FirmwareVersionPreferenceController;
import com.android.settings.deviceinfo.ImsStatusPreferenceController;
import com.android.settings.deviceinfo.IpAddressPreferenceController;
-import com.android.settings.deviceinfo.KernelVersionPreferenceController;
import com.android.settings.deviceinfo.ManualPreferenceController;
import com.android.settings.deviceinfo.PhoneNumberPreferenceController;
import com.android.settings.deviceinfo.RegulatoryInfoPreferenceController;
import com.android.settings.deviceinfo.SafetyInfoPreferenceController;
-import com.android.settings.deviceinfo.SecurityPatchPreferenceController;
import com.android.settings.deviceinfo.WifiMacAddressPreferenceController;
import com.android.settings.deviceinfo.firmwareversion.FirmwareVersionPreferenceControllerV2;
import com.android.settings.deviceinfo.imei.ImeiInfoPreferenceControllerV2;
@@ -84,21 +77,19 @@
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
final Bundle arguments = getArguments();
- if (FeatureFlagUtils.isEnabled(getContext(), DEVICE_INFO_V2)) {
- // Do not override initial expand children count if we come from
- // search (EXTRA_FRAGMENT_ARG_KEY is set) - we need to display every if entry point
- // is search.
- if (arguments == null
- || !arguments.containsKey(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY)) {
+ // Do not override initial expand children count if we come from
+ // search (EXTRA_FRAGMENT_ARG_KEY is set) - we need to display every if entry point
+ // is search.
+ if (arguments == null
+ || !arguments.containsKey(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY)) {
- // Increase the number of children when the device contains more than 1 sim.
- final TelephonyManager telephonyManager = (TelephonyManager) getSystemService(
- Context.TELEPHONY_SERVICE);
- final int numberOfChildren = Math.max(SIM_PREFERENCES_COUNT,
- SIM_PREFERENCES_COUNT * telephonyManager.getPhoneCount())
- + NON_SIM_PREFERENCES_COUNT;
- getPreferenceScreen().setInitialExpandedChildrenCount(numberOfChildren);
- }
+ // Increase the number of children when the device contains more than 1 sim.
+ final TelephonyManager telephonyManager = (TelephonyManager) getSystemService(
+ Context.TELEPHONY_SERVICE);
+ final int numberOfChildren = Math.max(SIM_PREFERENCES_COUNT,
+ SIM_PREFERENCES_COUNT * telephonyManager.getPhoneCount())
+ + NON_SIM_PREFERENCES_COUNT;
+ getPreferenceScreen().setInitialExpandedChildrenCount(numberOfChildren);
}
}
@@ -119,8 +110,7 @@
@Override
protected int getPreferenceScreenResId() {
- return FeatureFlagUtils.isEnabled(getContext(), DEVICE_INFO_V2)
- ? R.xml.device_info_settings_v2 : R.xml.device_info_settings;
+ return R.xml.device_info_settings_v2;
}
@Override
@@ -156,57 +146,23 @@
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
Activity activity, Fragment fragment, Lifecycle lifecycle) {
- if (FeatureFlagUtils.isEnabled(context, DEVICE_INFO_V2)) {
- final List<AbstractPreferenceController> controllers = new ArrayList<>();
- // Device name
-
- controllers.add(new PhoneNumberPreferenceController(context));
-
- controllers.add(new SimStatusPreferenceControllerV2(context, fragment));
-
- controllers.add(new DeviceModelPreferenceController(context, fragment));
-
- controllers.add(new ImeiInfoPreferenceControllerV2(context, fragment));
-
- controllers.add(new FirmwareVersionPreferenceControllerV2(context, fragment));
-
- controllers.add(new ImsStatusPreferenceController(context, lifecycle));
-
- controllers.add(new IpAddressPreferenceController(context, lifecycle));
-
- controllers.add(new WifiMacAddressPreferenceController(context, lifecycle));
-
- controllers.add(new BluetoothAddressPreferenceController(context, lifecycle));
-
- controllers.add(new RegulatoryInfoPreferenceController(context));
-
- controllers.add(new SafetyInfoPreferenceController(context));
-
- controllers.add(new ManualPreferenceController(context));
-
- controllers.add(new FeedbackPreferenceController(fragment, context));
-
- controllers.add(new FccEquipmentIdPreferenceController(context));
-
- controllers.add(
- new BuildNumberPreferenceController(context, activity, fragment, lifecycle));
-
- return controllers;
- }
-
final List<AbstractPreferenceController> controllers = new ArrayList<>();
- controllers.add(
- new BuildNumberPreferenceController(context, activity, fragment, lifecycle));
+ controllers.add(new PhoneNumberPreferenceController(context));
+ controllers.add(new SimStatusPreferenceControllerV2(context, fragment));
+ controllers.add(new DeviceModelPreferenceController(context, fragment));
+ controllers.add(new ImeiInfoPreferenceControllerV2(context, fragment));
+ controllers.add(new FirmwareVersionPreferenceControllerV2(context, fragment));
+ controllers.add(new ImsStatusPreferenceController(context, lifecycle));
+ controllers.add(new IpAddressPreferenceController(context, lifecycle));
+ controllers.add(new WifiMacAddressPreferenceController(context, lifecycle));
+ controllers.add(new BluetoothAddressPreferenceController(context, lifecycle));
+ controllers.add(new RegulatoryInfoPreferenceController(context));
+ controllers.add(new SafetyInfoPreferenceController(context));
controllers.add(new ManualPreferenceController(context));
controllers.add(new FeedbackPreferenceController(fragment, context));
- controllers.add(new KernelVersionPreferenceController(context));
- controllers.add(new BasebandVersionPreferenceController(context));
- controllers.add(new FirmwareVersionPreferenceController(context, lifecycle));
- controllers.add(new RegulatoryInfoPreferenceController(context));
- controllers.add(new DeviceModelPreferenceController(context, fragment));
- controllers.add(new SecurityPatchPreferenceController(context));
controllers.add(new FccEquipmentIdPreferenceController(context));
- controllers.add(new SafetyInfoPreferenceController(context));
+ controllers.add(
+ new BuildNumberPreferenceController(context, activity, fragment, lifecycle));
return controllers;
}
@@ -220,8 +176,7 @@
public List<SearchIndexableResource> getXmlResourcesToIndex(
Context context, boolean enabled) {
final SearchIndexableResource sir = new SearchIndexableResource(context);
- sir.xmlResId = FeatureFlagUtils.isEnabled(context, DEVICE_INFO_V2)
- ? R.xml.device_info_settings_v2 : R.xml.device_info_settings;
+ sir.xmlResId = R.xml.device_info_settings_v2;
return Arrays.asList(sir);
}
diff --git a/src/com/android/settings/PreviewSeekBarPreferenceFragment.java b/src/com/android/settings/PreviewSeekBarPreferenceFragment.java
index 544999a..f5f3017 100644
--- a/src/com/android/settings/PreviewSeekBarPreferenceFragment.java
+++ b/src/com/android/settings/PreviewSeekBarPreferenceFragment.java
@@ -58,6 +58,7 @@
private DotsPageIndicator mPageIndicator;
private TextView mLabel;
+ private LabeledSeekBar mSeekBar;
private View mLarger;
private View mSmaller;
@@ -110,19 +111,17 @@
// seek bar.
final int max = Math.max(1, mEntries.length - 1);
- final LabeledSeekBar seekBar = (LabeledSeekBar) content.findViewById(R.id.seek_bar);
- seekBar.setLabels(mEntries);
- seekBar.setMax(max);
- seekBar.setProgress(mInitialIndex);
- seekBar.setOnSeekBarChangeListener(new onPreviewSeekBarChangeListener());
+ mSeekBar = (LabeledSeekBar) content.findViewById(R.id.seek_bar);
+ mSeekBar.setLabels(mEntries);
+ mSeekBar.setMax(max);
mSmaller = content.findViewById(R.id.smaller);
mSmaller.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- final int progress = seekBar.getProgress();
+ final int progress = mSeekBar.getProgress();
if (progress > 0) {
- seekBar.setProgress(progress - 1, true);
+ mSeekBar.setProgress(progress - 1, true);
}
}
});
@@ -131,9 +130,9 @@
mLarger.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- final int progress = seekBar.getProgress();
- if (progress < seekBar.getMax()) {
- seekBar.setProgress(progress + 1, true);
+ final int progress = mSeekBar.getProgress();
+ if (progress < mSeekBar.getMax()) {
+ mSeekBar.setProgress(progress + 1, true);
}
}
});
@@ -141,7 +140,7 @@
if (mEntries.length == 1) {
// The larger and smaller buttons will be disabled when we call
// setPreviewLayer() later in this method.
- seekBar.setEnabled(false);
+ mSeekBar.setEnabled(false);
}
final Context context = getContext();
@@ -172,6 +171,21 @@
return root;
}
+ @Override
+ public void onStart() {
+ super.onStart();
+ // Set SeekBar listener here to avoid onProgressChanged() is called
+ // during onRestoreInstanceState().
+ mSeekBar.setProgress(mCurrentIndex);
+ mSeekBar.setOnSeekBarChangeListener(new onPreviewSeekBarChangeListener());
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ mSeekBar.setOnSeekBarChangeListener(null);
+ }
+
/**
* Creates new configuration based on the current position of the SeekBar.
*/
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index ff0f59f..9314952 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -148,9 +148,6 @@
public static class ApnEditorActivity extends SettingsActivity { /* empty */ }
public static class ChooseAccountActivity extends SettingsActivity { /* empty */ }
public static class IccLockSettingsActivity extends SettingsActivity { /* empty */ }
- public static class ImeiInformationActivity extends SettingsActivity { /* empty */ }
- public static class SimStatusActivity extends SettingsActivity { /* empty */ }
- public static class StatusActivity extends SettingsActivity { /* empty */ }
public static class TestingSettingsActivity extends SettingsActivity { /* empty */ }
public static class WifiAPITestActivity extends SettingsActivity { /* empty */ }
public static class WifiInfoActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 0611b09..2161415 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -42,6 +42,7 @@
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityManager;
+import com.android.internal.accessibility.AccessibilityShortcutController;
import com.android.internal.content.PackageMonitor;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.view.RotationPolicy;
@@ -57,6 +58,7 @@
import com.android.settingslib.accessibility.AccessibilityUtils;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -172,13 +174,7 @@
}
};
- private final SettingsContentObserver mSettingsContentObserver =
- new SettingsContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- updateServicePreferences();
- }
- };
+ private final SettingsContentObserver mSettingsContentObserver;
private final RotationPolicyListener mRotationPolicyListener = new RotationPolicyListener() {
@Override
@@ -224,6 +220,22 @@
.getBoolean(com.android.internal.R.bool.config_setColorTransformAccelerated);
}
+ public AccessibilitySettings() {
+ // Observe changes to anything that the shortcut can toggle, so we can reflect updates
+ final Collection<AccessibilityShortcutController.ToggleableFrameworkFeatureInfo> features =
+ AccessibilityShortcutController.getFrameworkShortcutFeaturesMap().values();
+ final List<String> shortcutFeatureKeys = new ArrayList<>(features.size());
+ for (AccessibilityShortcutController.ToggleableFrameworkFeatureInfo feature : features) {
+ shortcutFeatureKeys.add(feature.getSettingKey());
+ }
+ mSettingsContentObserver = new SettingsContentObserver(mHandler, shortcutFeatureKeys) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updateAllPreferences();
+ }
+ };
+ }
+
@Override
public int getMetricsCategory() {
return MetricsEvent.ACCESSIBILITY;
diff --git a/src/com/android/settings/accessibility/SettingsContentObserver.java b/src/com/android/settings/accessibility/SettingsContentObserver.java
index c3baec5..de67f6c 100644
--- a/src/com/android/settings/accessibility/SettingsContentObserver.java
+++ b/src/com/android/settings/accessibility/SettingsContentObserver.java
@@ -22,16 +22,28 @@
import android.os.Handler;
import android.provider.Settings;
+import java.util.ArrayList;
+import java.util.List;
+
abstract class SettingsContentObserver extends ContentObserver {
+ private final List<String> mKeysToObserve = new ArrayList<>(2);
+
public SettingsContentObserver(Handler handler) {
super(handler);
+ mKeysToObserve.add(Settings.Secure.ACCESSIBILITY_ENABLED);
+ mKeysToObserve.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+ }
+
+ public SettingsContentObserver(Handler handler, List<String> keysToObserve) {
+ this(handler);
+ mKeysToObserve.addAll(keysToObserve);
}
public void register(ContentResolver contentResolver) {
- contentResolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_ENABLED), false, this);
- contentResolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES), false, this);
+ for (int i = 0; i < mKeysToObserve.size(); i++) {
+ contentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(mKeysToObserve.get(i)), false, this);
+ }
}
public void unregister(ContentResolver contentResolver) {
diff --git a/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java b/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java
index e0c41be..52c1a0d 100644
--- a/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java
+++ b/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java
@@ -16,6 +16,8 @@
package com.android.settings.accessibility;
import static android.content.DialogInterface.BUTTON_POSITIVE;
+import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Activity;
@@ -85,9 +87,16 @@
Map<ComponentName, ToggleableFrameworkFeatureInfo> frameworkFeatureInfoMap =
AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
for (ComponentName componentName : frameworkFeatureInfoMap.keySet()) {
- // Lookup icon
+ final int iconId;
+ if (componentName.equals(COLOR_INVERSION_COMPONENT_NAME)) {
+ iconId = R.drawable.ic_color_inversion;
+ } else if (componentName.equals(DALTONIZER_COMPONENT_NAME)) {
+ iconId = R.drawable.ic_daltonizer;
+ } else {
+ iconId = R.drawable.empty_icon;
+ }
candidates.add(new FrameworkCandidateInfo(frameworkFeatureInfoMap.get(componentName),
- R.drawable.empty_icon, componentName.flattenToString()));
+ iconId, componentName.flattenToString()));
}
for (int i = 0; i < numInstalledServices; i++) {
final AccessibilityServiceInfo installedServiceInfo = installedServices.get(i);
diff --git a/src/com/android/settings/applications/AppInfoDashboardFragment.java b/src/com/android/settings/applications/AppInfoDashboardFragment.java
deleted file mode 100755
index d7d91f3..0000000
--- a/src/com/android/settings/applications/AppInfoDashboardFragment.java
+++ /dev/null
@@ -1,1166 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.settings.applications;
-
-import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.Fragment;
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.content.pm.UserInfo;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.support.annotation.VisibleForTesting;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceCategory;
-import android.support.v7.preference.PreferenceScreen;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.webkit.IWebViewUpdateService;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settings.DeviceAdminAdd;
-import com.android.settings.R;
-import com.android.settings.SettingsActivity;
-import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.Utils;
-import com.android.settings.applications.appinfo.AppBatteryPreferenceController;
-import com.android.settings.applications.appinfo.AppDataUsagePreferenceController;
-import com.android.settings.applications.appinfo.AppMemoryPreferenceController;
-import com.android.settings.applications.appinfo.AppNotificationPreferenceController;
-import com.android.settings.applications.appinfo.AppOpenByDefaultPreferenceController;
-import com.android.settings.applications.appinfo.AppPermissionPreferenceController;
-import com.android.settings.applications.appinfo.AppStoragePreferenceController;
-import com.android.settings.applications.appinfo.AppVersionPreferenceController;
-import com.android.settings.applications.appinfo.DefaultBrowserShortcutPreferenceController;
-import com.android.settings.applications.appinfo.DefaultEmergencyShortcutPreferenceController;
-import com.android.settings.applications.appinfo.DefaultHomeShortcutPreferenceController;
-import com.android.settings.applications.appinfo.DefaultPhoneShortcutPreferenceController;
-import com.android.settings.applications.appinfo.DefaultSmsShortcutPreferenceController;
-import com.android.settings.applications.appinfo.DrawOverlayDetailPreferenceController;
-import com.android.settings.applications.appinfo.ExternalSourceDetailPreferenceController;
-import com.android.settings.applications.appinfo.PictureInPictureDetailPreferenceController;
-import com.android.settings.applications.appinfo.WriteSystemSettingsPreferenceController;
-import com.android.settings.applications.instantapps.InstantAppButtonsController;
-import com.android.settings.applications.manageapplications.ManageApplications;
-import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
-import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.overlay.FeatureFactory;
-import com.android.settings.widget.ActionButtonPreference;
-import com.android.settings.widget.EntityHeaderController;
-import com.android.settings.widget.PreferenceCategoryController;
-import com.android.settings.wrapper.DevicePolicyManagerWrapper;
-import com.android.settingslib.RestrictedLockUtils;
-import com.android.settingslib.applications.AppUtils;
-import com.android.settingslib.applications.ApplicationsState;
-import com.android.settingslib.applications.ApplicationsState.AppEntry;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Dashboard fragment to display application information from Settings. This activity presents
- * extended information associated with a package like code, data, total size, permissions
- * used by the application and also the set of default launchable activities.
- * For system applications, an option to clear user data is displayed only if data size is > 0.
- * System applications that do not want clear user data do not have this option.
- * For non-system applications, there is no option to clear data. Instead there is an option to
- * uninstall the application.
- */
-public class AppInfoDashboardFragment extends DashboardFragment
- implements ApplicationsState.Callbacks {
-
- private static final String TAG = "AppInfoDashboard";
-
- // Menu identifiers
- public static final int UNINSTALL_ALL_USERS_MENU = 1;
- public static final int UNINSTALL_UPDATES = 2;
-
- // Result code identifiers
- public static final int REQUEST_UNINSTALL = 0;
- private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1;
-
- public static final int SUB_INFO_FRAGMENT = 1;
-
- public static final int LOADER_CHART_DATA = 2;
- public static final int LOADER_STORAGE = 3;
- @VisibleForTesting
- public static final int LOADER_BATTERY = 4;
-
- // Dialog identifiers used in showDialog
- private static final int DLG_BASE = 0;
- private static final int DLG_FORCE_STOP = DLG_BASE + 1;
- private static final int DLG_DISABLE = DLG_BASE + 2;
- private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3;
- private static final String KEY_HEADER = "header_view";
- private static final String KEY_INSTANT_APP_BUTTONS = "instant_app_buttons";
- private static final String KEY_ACTION_BUTTONS = "action_buttons";
- private static final String KEY_INSTANT_APP_SUPPORTED_LINKS =
- "instant_app_launch_supported_domain_urls";
-
- public static final String ARG_PACKAGE_NAME = "package";
- public static final String ARG_PACKAGE_UID = "uid";
-
- protected static final boolean localLOGV = false;
- private static final String KEY_ADVANCED_APP_INFO_CATEGORY = "advanced_app_info";
-
- private EnforcedAdmin mAppsControlDisallowedAdmin;
- private boolean mAppsControlDisallowedBySystem;
-
- private ApplicationFeatureProvider mApplicationFeatureProvider;
- private ApplicationsState mState;
- private ApplicationsState.Session mSession;
- private ApplicationsState.AppEntry mAppEntry;
- private PackageInfo mPackageInfo;
- private int mUserId;
- private String mPackageName;
-
- private DevicePolicyManagerWrapper mDpm;
- private UserManager mUserManager;
- private PackageManager mPm;
-
- private boolean mFinishing;
- private boolean mListeningToPackageRemove;
-
-
- private final HashSet<String> mHomePackages = new HashSet<>();
-
- private boolean mInitialized;
- private boolean mShowUninstalled;
- private LayoutPreference mHeader;
- private boolean mUpdatedSysApp = false;
- private AppDomainsPreference mInstantAppDomainsPreference;
- private boolean mDisableAfterUninstall;
-
- private List<Callback> mCallbacks = new ArrayList<>();
-
- @VisibleForTesting
- ActionButtonPreference mActionButtons;
-
- private InstantAppButtonsController mInstantAppButtonsController;
-
- /**
- * Callback to invoke when app info has been changed.
- */
- public interface Callback {
- void refreshUi();
- }
-
- @VisibleForTesting
- boolean handleDisableable() {
- boolean disableable = false;
- // Try to prevent the user from bricking their phone
- // by not allowing disabling of apps signed with the
- // system cert and any launcher app in the system.
- if (mHomePackages.contains(mAppEntry.info.packageName)
- || Utils.isSystemPackage(getContext().getResources(), mPm, mPackageInfo)) {
- // Disable button for core system applications.
- mActionButtons
- .setButton1Text(R.string.disable_text)
- .setButton1Positive(false);
- } else if (mAppEntry.info.enabled && !isDisabledUntilUsed()) {
- mActionButtons
- .setButton1Text(R.string.disable_text)
- .setButton1Positive(false);
- disableable = !mApplicationFeatureProvider.getKeepEnabledPackages()
- .contains(mAppEntry.info.packageName);
- } else {
- mActionButtons
- .setButton1Text(R.string.enable_text)
- .setButton1Positive(true);
- disableable = true;
- }
-
- return disableable;
- }
-
- private boolean isDisabledUntilUsed() {
- return mAppEntry.info.enabledSetting
- == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
- }
-
- private void initUninstallButtons() {
- final boolean isBundled = (mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
- boolean enabled;
- if (isBundled) {
- enabled = handleDisableable();
- } else {
- enabled = initUninstallButtonForUserApp();
- }
- // If this is a device admin, it can't be uninstalled or disabled.
- // We do this here so the text of the button is still set correctly.
- if (isBundled && mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
- enabled = false;
- }
-
- // We don't allow uninstalling DO/PO on *any* users, because if it's a system app,
- // "uninstall" is actually "downgrade to the system version + disable", and "downgrade"
- // will clear data on all users.
- if (Utils.isProfileOrDeviceOwner(mUserManager, mDpm, mPackageInfo.packageName)) {
- enabled = false;
- }
-
- // Don't allow uninstalling the device provisioning package.
- if (Utils.isDeviceProvisioningPackage(getResources(), mAppEntry.info.packageName)) {
- enabled = false;
- }
-
- // If the uninstall intent is already queued, disable the uninstall button
- if (mDpm.isUninstallInQueue(mPackageName)) {
- enabled = false;
- }
-
- // Home apps need special handling. Bundled ones we don't risk downgrading
- // because that can interfere with home-key resolution. Furthermore, we
- // can't allow uninstallation of the only home app, and we don't want to
- // allow uninstallation of an explicitly preferred one -- the user can go
- // to Home settings and pick a different one, after which we'll permit
- // uninstallation of the now-not-default one.
- if (enabled && mHomePackages.contains(mPackageInfo.packageName)) {
- if (isBundled) {
- enabled = false;
- } else {
- ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
- ComponentName currentDefaultHome = mPm.getHomeActivities(homeActivities);
- if (currentDefaultHome == null) {
- // No preferred default, so permit uninstall only when
- // there is more than one candidate
- enabled = (mHomePackages.size() > 1);
- } else {
- // There is an explicit default home app -- forbid uninstall of
- // that one, but permit it for installed-but-inactive ones.
- enabled = !mPackageInfo.packageName.equals(currentDefaultHome.getPackageName());
- }
- }
- }
-
- if (mAppsControlDisallowedBySystem) {
- enabled = false;
- }
-
- try {
- IWebViewUpdateService webviewUpdateService =
- IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
- if (webviewUpdateService.isFallbackPackage(mAppEntry.info.packageName)) {
- enabled = false;
- }
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
-
- mActionButtons.setButton1Enabled(enabled);
- if (enabled) {
- // Register listener
- mActionButtons.setButton1OnClickListener(v -> handleUninstallButtonClick());
- }
- }
-
- @VisibleForTesting
- boolean initUninstallButtonForUserApp() {
- boolean enabled = true;
- if ((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) == 0
- && mUserManager.getUsers().size() >= 2) {
- // When we have multiple users, there is a separate menu
- // to uninstall for all users.
- enabled = false;
- } else if (AppUtils.isInstant(mPackageInfo.applicationInfo)) {
- enabled = false;
- mActionButtons.setButton1Visible(false);
- }
- mActionButtons.setButton1Text(R.string.uninstall_text).setButton1Positive(false);
- return enabled;
- }
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- mFinishing = false;
- final Activity activity = getActivity();
- mApplicationFeatureProvider = FeatureFactory.getFactory(activity)
- .getApplicationFeatureProvider(activity);
- mDpm = new DevicePolicyManagerWrapper(
- (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE));
- mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE);
- mPm = activity.getPackageManager();
-
- retrieveAppEntry();
- startListeningToPackageRemove();
-
- if (!ensurePackageInfoAvailable(activity)) {
- return;
- }
-
- setHasOptionsMenu(true);
-
- addDynamicPrefs();
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.APPLICATIONS_INSTALLED_APP_DETAILS;
- }
-
- @Override
- public void onResume() {
- super.onResume();
- mAppsControlDisallowedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(getActivity(),
- UserManager.DISALLOW_APPS_CONTROL, mUserId);
- mAppsControlDisallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction(getActivity(),
- UserManager.DISALLOW_APPS_CONTROL, mUserId);
-
- if (!refreshUi()) {
- setIntentAndFinish(true, true);
- }
- }
-
- @Override
- protected int getPreferenceScreenResId() {
- return R.xml.app_info_settings;
- }
-
- @Override
- protected String getLogTag() {
- return TAG;
- }
-
- @Override
- protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
- final String packageName = getPackageName();
- final List<AbstractPreferenceController> controllers = new ArrayList<>();
- final Lifecycle lifecycle = getLifecycle();
-
- // The following are controllers for preferences that needs to refresh the preference state
- // when app state changes.
- controllers.add(new AppStoragePreferenceController(context, this, lifecycle));
- controllers.add(new AppDataUsagePreferenceController(context, this, lifecycle));
- controllers.add(new AppNotificationPreferenceController(context, this));
- controllers.add(new AppOpenByDefaultPreferenceController(context, this));
- controllers.add(new AppPermissionPreferenceController(context, this, packageName));
- controllers.add(new AppVersionPreferenceController(context, this));
-
- for (AbstractPreferenceController controller : controllers) {
- mCallbacks.add((Callback) controller);
- }
-
- // The following are controllers for preferences that don't need to refresh the preference
- // state when app state changes.
- controllers.add(new AppBatteryPreferenceController(context, this, packageName, lifecycle));
- controllers.add(new AppMemoryPreferenceController(context, this, lifecycle));
- controllers.add(new DefaultHomeShortcutPreferenceController(context, packageName));
- controllers.add(new DefaultBrowserShortcutPreferenceController(context, packageName));
- controllers.add(new DefaultPhoneShortcutPreferenceController(context, packageName));
- controllers.add(new DefaultEmergencyShortcutPreferenceController(context, packageName));
- controllers.add(new DefaultSmsShortcutPreferenceController(context, packageName));
-
- final List<AbstractPreferenceController> advancedAppInfoControllers = new ArrayList<>();
- advancedAppInfoControllers.add(new DrawOverlayDetailPreferenceController(context, this));
- advancedAppInfoControllers.add(new WriteSystemSettingsPreferenceController(context, this));
- advancedAppInfoControllers.add(
- new PictureInPictureDetailPreferenceController(context, this, packageName));
- advancedAppInfoControllers.add(
- new ExternalSourceDetailPreferenceController(context, this, packageName));
- controllers.addAll(advancedAppInfoControllers);
- controllers.add(new PreferenceCategoryController(
- context, KEY_ADVANCED_APP_INFO_CATEGORY, advancedAppInfoControllers));
-
- return controllers;
- }
-
- public ApplicationsState.AppEntry getAppEntry() {
- if (mAppEntry == null) {
- retrieveAppEntry();
- }
- return mAppEntry;
- }
-
- public PackageInfo getPackageInfo() {
- if (mAppEntry == null) {
- retrieveAppEntry();
- }
- return mPackageInfo;
- }
-
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- if (mFinishing) {
- return;
- }
- final Activity activity = getActivity();
- mHeader = (LayoutPreference) findPreference(KEY_HEADER);
- mActionButtons = ((ActionButtonPreference) findPreference(KEY_ACTION_BUTTONS))
- .setButton2Text(R.string.force_stop)
- .setButton2Positive(false)
- .setButton2Enabled(false);
- EntityHeaderController.newInstance(activity, this, mHeader.findViewById(R.id.entity_header))
- .setRecyclerView(getListView(), getLifecycle())
- .setPackageName(mPackageName)
- .setHasAppInfoLink(false)
- .setButtonActions(EntityHeaderController.ActionType.ACTION_APP_PREFERENCE,
- EntityHeaderController.ActionType.ACTION_NONE)
- .styleActionBar(activity)
- .bindHeaderButtons();
-
- mInstantAppDomainsPreference =
- (AppDomainsPreference) findPreference(KEY_INSTANT_APP_SUPPORTED_LINKS);
- }
-
- @Override
- public void onPackageSizeChanged(String packageName) {
- if (!TextUtils.equals(packageName, mPackageName)) {
- Log.d(TAG, "Package change irrelevant, skipping");
- return;
- }
- refreshUi();
- }
-
- /**
- * Ensures the {@link PackageInfo} is available to proceed. If it's not available, the fragment
- * will finish.
- *
- * @return true if packageInfo is available.
- */
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- boolean ensurePackageInfoAvailable(Activity activity) {
- if (mPackageInfo == null) {
- mFinishing = true;
- Log.w(TAG, "Package info not available. Is this package already uninstalled?");
- activity.finishAndRemoveTask();
- return false;
- }
- return true;
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- super.onCreateOptionsMenu(menu, inflater);
- menu.add(0, UNINSTALL_UPDATES, 0, R.string.app_factory_reset)
- .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
- menu.add(0, UNINSTALL_ALL_USERS_MENU, 1, R.string.uninstall_all_users_text)
- .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
- }
-
- @Override
- public void onPrepareOptionsMenu(Menu menu) {
- if (mFinishing) {
- return;
- }
- menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(shouldShowUninstallForAll(mAppEntry));
- mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
- MenuItem uninstallUpdatesItem = menu.findItem(UNINSTALL_UPDATES);
- uninstallUpdatesItem.setVisible(mUpdatedSysApp && !mAppsControlDisallowedBySystem);
- if (uninstallUpdatesItem.isVisible()) {
- RestrictedLockUtils.setMenuItemAsDisabledByAdmin(getActivity(),
- uninstallUpdatesItem, mAppsControlDisallowedAdmin);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case UNINSTALL_ALL_USERS_MENU:
- uninstallPkg(mAppEntry.info.packageName, true, false);
- return true;
- case UNINSTALL_UPDATES:
- uninstallPkg(mAppEntry.info.packageName, false, false);
- return true;
- }
- return false;
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- switch (requestCode) {
- case REQUEST_UNINSTALL:
- // Refresh option menu
- getActivity().invalidateOptionsMenu();
-
- if (mDisableAfterUninstall) {
- mDisableAfterUninstall = false;
- new DisableChanger(this, mAppEntry.info,
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
- .execute((Object)null);
- }
- // continue with following operations
- case REQUEST_REMOVE_DEVICE_ADMIN:
- if (!refreshUi()) {
- setIntentAndFinish(true, true);
- } else {
- startListeningToPackageRemove();
- }
- break;
- }
- }
-
- /**
- * Utility method to hide and show specific preferences based on whether the app being displayed
- * is an Instant App or an installed app.
- */
- @VisibleForTesting
- void prepareInstantAppPrefs() {
- final boolean isInstant = AppUtils.isInstant(mPackageInfo.applicationInfo);
- if (isInstant) {
- Set<String> handledDomainSet = Utils.getHandledDomains(mPm, mPackageInfo.packageName);
- String[] handledDomains = handledDomainSet.toArray(new String[handledDomainSet.size()]);
- mInstantAppDomainsPreference.setTitles(handledDomains);
- // Dummy values, unused in the implementation
- mInstantAppDomainsPreference.setValues(new int[handledDomains.length]);
- } else {
- getPreferenceScreen().removePreference(mInstantAppDomainsPreference);
- }
- }
-
- // Utility method to set application label and icon.
- private void setAppLabelAndIcon(PackageInfo pkgInfo) {
- final View appSnippet = mHeader.findViewById(R.id.entity_header);
- mState.ensureIcon(mAppEntry);
- final Activity activity = getActivity();
- final boolean isInstantApp = AppUtils.isInstant(mPackageInfo.applicationInfo);
- final CharSequence summary =
- isInstantApp ? null : getString(Utils.getInstallationStatus(mAppEntry.info));
- EntityHeaderController.newInstance(activity, this, appSnippet)
- .setLabel(mAppEntry)
- .setIcon(mAppEntry)
- .setSummary(summary)
- .setIsInstantApp(isInstantApp)
- .done(activity, false /* rebindActions */);
- }
-
- @VisibleForTesting
- boolean shouldShowUninstallForAll(AppEntry appEntry) {
- boolean showIt = true;
- if (mUpdatedSysApp) {
- showIt = false;
- } else if (appEntry == null) {
- showIt = false;
- } else if ((appEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- showIt = false;
- } else if (mPackageInfo == null || mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
- showIt = false;
- } else if (UserHandle.myUserId() != 0) {
- showIt = false;
- } else if (mUserManager.getUsers().size() < 2) {
- showIt = false;
- } else if (PackageUtil.countPackageInUsers(mPm, mUserManager, mPackageName) < 2
- && (appEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
- showIt = false;
- } else if (AppUtils.isInstant(appEntry.info)) {
- showIt = false;
- }
- return showIt;
- }
-
- private boolean signaturesMatch(String pkg1, String pkg2) {
- if (pkg1 != null && pkg2 != null) {
- try {
- final int match = mPm.checkSignatures(pkg1, pkg2);
- if (match >= PackageManager.SIGNATURE_MATCH) {
- return true;
- }
- } catch (Exception e) {
- // e.g. named alternate package not found during lookup;
- // this is an expected case sometimes
- }
- }
- return false;
- }
-
- @VisibleForTesting
- boolean refreshUi() {
- retrieveAppEntry();
- if (mAppEntry == null) {
- return false; // onCreate must have failed, make sure to exit
- }
-
- if (mPackageInfo == null) {
- return false; // onCreate must have failed, make sure to exit
- }
-
- // Get list of "home" apps and trace through any meta-data references
- List<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
- mPm.getHomeActivities(homeActivities);
- mHomePackages.clear();
- for (int i = 0; i< homeActivities.size(); i++) {
- ResolveInfo ri = homeActivities.get(i);
- final String activityPkg = ri.activityInfo.packageName;
- mHomePackages.add(activityPkg);
-
- // Also make sure to include anything proxying for the home app
- final Bundle metadata = ri.activityInfo.metaData;
- if (metadata != null) {
- final String metaPkg = metadata.getString(ActivityManager.META_HOME_ALTERNATE);
- if (signaturesMatch(metaPkg, activityPkg)) {
- mHomePackages.add(metaPkg);
- }
- }
- }
-
- checkForceStop();
- setAppLabelAndIcon(mPackageInfo);
- initUninstallButtons();
- prepareInstantAppPrefs();
-
- // Update the preference summaries.
- Activity context = getActivity();
- for (Callback callback : mCallbacks) {
- callback.refreshUi();
- }
-
- if (!mInitialized) {
- // First time init: are we displaying an uninstalled app?
- mInitialized = true;
- mShowUninstalled = (mAppEntry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0;
- } else {
- // All other times: if the app no longer exists then we want
- // to go away.
- try {
- ApplicationInfo ainfo = context.getPackageManager().getApplicationInfo(
- mAppEntry.info.packageName,
- PackageManager.MATCH_DISABLED_COMPONENTS
- | PackageManager.MATCH_ANY_USER);
- if (!mShowUninstalled) {
- // If we did not start out with the app uninstalled, then
- // it transitioning to the uninstalled state for the current
- // user means we should go away as well.
- return (ainfo.flags&ApplicationInfo.FLAG_INSTALLED) != 0;
- }
- } catch (NameNotFoundException e) {
- return false;
- }
- }
-
- return true;
- }
-
- protected AlertDialog createDialog(int id, int errorCode) {
- switch (id) {
- case DLG_DISABLE:
- return new AlertDialog.Builder(getActivity())
- .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
- .setPositiveButton(R.string.app_disable_dlg_positive,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Disable the app
- mMetricsFeatureProvider.action(getContext(),
- MetricsEvent.ACTION_SETTINGS_DISABLE_APP);
- new DisableChanger(AppInfoDashboardFragment.this, mAppEntry.info,
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
- .execute((Object)null);
- }
- })
- .setNegativeButton(R.string.dlg_cancel, null)
- .create();
- case DLG_SPECIAL_DISABLE:
- return new AlertDialog.Builder(getActivity())
- .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
- .setPositiveButton(R.string.app_disable_dlg_positive,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Disable the app and ask for uninstall
- mMetricsFeatureProvider.action(getContext(),
- MetricsEvent.ACTION_SETTINGS_DISABLE_APP);
- uninstallPkg(mAppEntry.info.packageName,
- false, true);
- }
- })
- .setNegativeButton(R.string.dlg_cancel, null)
- .create();
- case DLG_FORCE_STOP:
- return new AlertDialog.Builder(getActivity())
- .setTitle(getActivity().getText(R.string.force_stop_dlg_title))
- .setMessage(getActivity().getText(R.string.force_stop_dlg_text))
- .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Force stop
- forceStopPackage(mAppEntry.info.packageName);
- }
- })
- .setNegativeButton(R.string.dlg_cancel, null)
- .create();
- }
- if (mInstantAppButtonsController != null) {
- return mInstantAppButtonsController.createDialog(id);
- }
- return null;
- }
-
- private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) {
- stopListeningToPackageRemove();
- // Create new intent to launch Uninstaller activity
- Uri packageURI = Uri.parse("package:"+packageName);
- Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
- uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
- mMetricsFeatureProvider.action(
- getContext(), MetricsEvent.ACTION_SETTINGS_UNINSTALL_APP);
- startActivityForResult(uninstallIntent, REQUEST_UNINSTALL);
- mDisableAfterUninstall = andDisable;
- }
-
- private void forceStopPackage(String pkgName) {
- mMetricsFeatureProvider.action(getContext(), MetricsEvent.ACTION_APP_FORCE_STOP, pkgName);
- ActivityManager am = (ActivityManager) getActivity().getSystemService(
- Context.ACTIVITY_SERVICE);
- Log.d(TAG, "Stopping package " + pkgName);
- am.forceStopPackage(pkgName);
- int userId = UserHandle.getUserId(mAppEntry.info.uid);
- mState.invalidatePackage(pkgName, userId);
- AppEntry newEnt = mState.getEntry(pkgName, userId);
- if (newEnt != null) {
- mAppEntry = newEnt;
- }
- checkForceStop();
- }
-
- private void updateForceStopButton(boolean enabled) {
- mActionButtons
- .setButton2Enabled(mAppsControlDisallowedBySystem ? false : enabled)
- .setButton2OnClickListener(mAppsControlDisallowedBySystem
- ? null : v -> handleForceStopButtonClick());
- }
-
- @VisibleForTesting
- void checkForceStop() {
- if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
- // User can't force stop device admin.
- Log.w(TAG, "User can't force stop device admin");
- updateForceStopButton(false);
- } else if (AppUtils.isInstant(mPackageInfo.applicationInfo)) {
- updateForceStopButton(false);
- mActionButtons.setButton2Visible(false);
- } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_STOPPED) == 0) {
- // If the app isn't explicitly stopped, then always show the
- // force stop button.
- Log.w(TAG, "App is not explicitly stopped");
- updateForceStopButton(true);
- } else {
- Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
- Uri.fromParts("package", mAppEntry.info.packageName, null));
- intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { mAppEntry.info.packageName });
- intent.putExtra(Intent.EXTRA_UID, mAppEntry.info.uid);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mAppEntry.info.uid));
- Log.d(TAG, "Sending broadcast to query restart status for "
- + mAppEntry.info.packageName);
- getActivity().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
- mCheckKillProcessesReceiver, null, Activity.RESULT_CANCELED, null, null);
- }
- }
-
- public static void startAppInfoFragment(Class<?> fragment, int title,
- SettingsPreferenceFragment caller, AppEntry appEntry) {
- // start new fragment to display extended information
- Bundle args = new Bundle();
- args.putString(ARG_PACKAGE_NAME, appEntry.info.packageName);
- args.putInt(ARG_PACKAGE_UID, appEntry.info.uid);
-
- SettingsActivity sa = (SettingsActivity) caller.getActivity();
- sa.startPreferencePanel(caller, fragment.getName(), args, title, null, caller,
- SUB_INFO_FRAGMENT);
- }
-
- private void handleUninstallButtonClick() {
- if (mAppEntry == null) {
- setIntentAndFinish(true, true);
- return;
- }
- final String packageName = mAppEntry.info.packageName;
- if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
- stopListeningToPackageRemove();
- Activity activity = getActivity();
- Intent uninstallDAIntent = new Intent(activity, DeviceAdminAdd.class);
- uninstallDAIntent.putExtra(DeviceAdminAdd.EXTRA_DEVICE_ADMIN_PACKAGE_NAME,
- mPackageName);
- mMetricsFeatureProvider.action(
- activity, MetricsEvent.ACTION_SETTINGS_UNINSTALL_DEVICE_ADMIN);
- activity.startActivityForResult(uninstallDAIntent, REQUEST_REMOVE_DEVICE_ADMIN);
- return;
- }
- EnforcedAdmin admin = RestrictedLockUtils.checkIfUninstallBlocked(getActivity(),
- packageName, mUserId);
- boolean uninstallBlockedBySystem = mAppsControlDisallowedBySystem ||
- RestrictedLockUtils.hasBaseUserRestriction(getActivity(), packageName, mUserId);
- if (admin != null && !uninstallBlockedBySystem) {
- RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(), admin);
- } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- if (mAppEntry.info.enabled && !isDisabledUntilUsed()) {
- // If the system app has an update and this is the only user on the device,
- // then offer to downgrade the app, otherwise only offer to disable the
- // app for this user.
- if (mUpdatedSysApp && isSingleUser()) {
- showDialogInner(DLG_SPECIAL_DISABLE, 0);
- } else {
- showDialogInner(DLG_DISABLE, 0);
- }
- } else {
- mMetricsFeatureProvider.action(
- getActivity(),
- MetricsEvent.ACTION_SETTINGS_ENABLE_APP);
- new DisableChanger(this, mAppEntry.info,
- PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
- .execute((Object) null);
- }
- } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
- uninstallPkg(packageName, true, false);
- } else {
- uninstallPkg(packageName, false, false);
- }
- }
-
- private void handleForceStopButtonClick() {
- if (mAppEntry == null) {
- setIntentAndFinish(true, true);
- return;
- }
- if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
- RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
- getActivity(), mAppsControlDisallowedAdmin);
- } else {
- showDialogInner(DLG_FORCE_STOP, 0);
- //forceStopPackage(mAppInfo.packageName);
- }
- }
-
- /** Returns whether there is only one user on this device, not including the system-only user */
- private boolean isSingleUser() {
- final int userCount = mUserManager.getUserCount();
- return userCount == 1
- || (mUserManager.isSplitSystemUser() && userCount == 2);
- }
-
- private void addDynamicPrefs() {
- if (UserManager.get(getContext()).isManagedProfile()) {
- return;
- }
- addAppInstallerInfoPref(getPreferenceScreen());
- maybeAddInstantAppButtons();
- }
-
- private void addAppInstallerInfoPref(PreferenceScreen screen) {
- String installerPackageName =
- AppStoreUtil.getInstallerPackageName(getContext(), mPackageName);
-
- final CharSequence installerLabel = Utils.getApplicationLabel(getContext(),
- installerPackageName);
- if (installerLabel == null) {
- return;
- }
- final int detailsStringId = AppUtils.isInstant(mPackageInfo.applicationInfo)
- ? R.string.instant_app_details_summary
- : R.string.app_install_details_summary;
- PreferenceCategory category = new PreferenceCategory(getPrefContext());
- category.setTitle(R.string.app_install_details_group_title);
- screen.addPreference(category);
- Preference pref = new Preference(getPrefContext());
- pref.setTitle(R.string.app_install_details_title);
- pref.setKey("app_info_store");
- pref.setSummary(getString(detailsStringId, installerLabel));
-
- Intent intent =
- AppStoreUtil.getAppStoreLink(getContext(), installerPackageName, mPackageName);
- if (intent != null) {
- pref.setIntent(intent);
- } else {
- pref.setEnabled(false);
- }
- category.addPreference(pref);
- }
-
- @VisibleForTesting
- void maybeAddInstantAppButtons() {
- if (AppUtils.isInstant(mPackageInfo.applicationInfo)) {
- LayoutPreference buttons = (LayoutPreference) findPreference(KEY_INSTANT_APP_BUTTONS);
- mInstantAppButtonsController = mApplicationFeatureProvider
- .newInstantAppButtonsController(this,
- buttons.findViewById(R.id.instant_app_button_container),
- id -> showDialogInner(id, 0))
- .setPackageName(mPackageName)
- .show();
- }
- }
-
- private void onPackageRemoved() {
- getActivity().finishActivity(SUB_INFO_FRAGMENT);
- getActivity().finishAndRemoveTask();
- }
-
- /**
- * Elicit this class for testing. Test cannot be done in robolectric because it
- * invokes the new API.
- */
- @VisibleForTesting
- public static class PackageUtil {
- /**
- * Count how many users in device have installed package {@paramref packageName}
- */
- public static int countPackageInUsers(PackageManager packageManager, UserManager
- userManager, String packageName) {
- final List<UserInfo> userInfos = userManager.getUsers(true);
- int count = 0;
-
- for (final UserInfo userInfo : userInfos) {
- try {
- // Use this API to check whether user has this package
- final ApplicationInfo info = packageManager.getApplicationInfoAsUser(
- packageName, PackageManager.GET_META_DATA, userInfo.id);
- if ((info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
- count++;
- }
- } catch(NameNotFoundException e) {
- Log.e(TAG, "Package: " + packageName + " not found for user: " + userInfo.id);
- }
- }
-
- return count;
- }
- }
-
- private static class DisableChanger extends AsyncTask<Object, Object, Object> {
- final PackageManager mPm;
- final WeakReference<AppInfoDashboardFragment> mActivity;
- final ApplicationInfo mInfo;
- final int mState;
-
- DisableChanger(AppInfoDashboardFragment activity, ApplicationInfo info, int state) {
- mPm = activity.mPm;
- mActivity = new WeakReference<AppInfoDashboardFragment>(activity);
- mInfo = info;
- mState = state;
- }
-
- @Override
- protected Object doInBackground(Object... params) {
- mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0);
- return null;
- }
- }
-
- private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final boolean enabled = getResultCode() != Activity.RESULT_CANCELED;
- Log.d(TAG, "Got broadcast response: Restart status for "
- + mAppEntry.info.packageName + " " + enabled);
- updateForceStopButton(enabled);
- }
- };
-
- private String getPackageName() {
- if (mPackageName != null) {
- return mPackageName;
- }
- final Bundle args = getArguments();
- mPackageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null;
- if (mPackageName == null) {
- Intent intent = (args == null) ?
- getActivity().getIntent() : (Intent) args.getParcelable("intent");
- if (intent != null) {
- mPackageName = intent.getData().getSchemeSpecificPart();
- }
- }
- return mPackageName;
- }
-
- private void retrieveAppEntry() {
- final Activity activity = getActivity();
- if (activity == null) {
- return;
- }
- if (mState == null) {
- mState = ApplicationsState.getInstance(activity.getApplication());
- mSession = mState.newSession(this, getLifecycle());
- }
- mUserId = UserHandle.myUserId();
- mAppEntry = mState.getEntry(getPackageName(), UserHandle.myUserId());
- if (mAppEntry != null) {
- // Get application info again to refresh changed properties of application
- try {
- mPackageInfo = activity.getPackageManager().getPackageInfo(
- mAppEntry.info.packageName,
- PackageManager.MATCH_DISABLED_COMPONENTS |
- PackageManager.MATCH_ANY_USER |
- PackageManager.GET_SIGNATURES |
- PackageManager.GET_PERMISSIONS);
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Exception when retrieving package:" + mAppEntry.info.packageName, e);
- }
- } else {
- Log.w(TAG, "Missing AppEntry; maybe reinstalling?");
- mPackageInfo = null;
- }
- }
-
- private void setIntentAndFinish(boolean finish, boolean appChanged) {
- if (localLOGV) Log.i(TAG, "appChanged="+appChanged);
- Intent intent = new Intent();
- intent.putExtra(ManageApplications.APP_CHG, appChanged);
- SettingsActivity sa = (SettingsActivity)getActivity();
- sa.finishPreferencePanel(this, Activity.RESULT_OK, intent);
- mFinishing = true;
- }
-
- private void showDialogInner(int id, int moveErrorCode) {
- DialogFragment newFragment =
- AppInfoBase.MyAlertDialogFragment.newInstance(id, moveErrorCode);
- newFragment.setTargetFragment(this, 0);
- newFragment.show(getFragmentManager(), "dialog " + id);
- }
-
- @Override
- public void onRunningStateChanged(boolean running) {
- // No op.
- }
-
- @Override
- public void onRebuildComplete(ArrayList<AppEntry> apps) {
- // No op.
- }
-
- @Override
- public void onPackageIconChanged() {
- // No op.
- }
-
- @Override
- public void onAllSizesComputed() {
- // No op.
- }
-
- @Override
- public void onLauncherInfoChanged() {
- // No op.
- }
-
- @Override
- public void onLoadEntriesCompleted() {
- // No op.
- }
-
- @Override
- public void onPackageListChanged() {
- if (!refreshUi()) {
- setIntentAndFinish(true, true);
- }
- }
-
- public static void startAppInfoFragment(Class<?> fragment, int titleRes,
- String pkg, int uid, Fragment source, int request, int sourceMetricsCategory) {
- startAppInfoFragment(fragment, titleRes, pkg, uid, source.getActivity(), request,
- sourceMetricsCategory);
- }
-
- public static void startAppInfoFragment(Class<?> fragment, int titleRes,
- String pkg, int uid, Activity source, int request, int sourceMetricsCategory) {
- Bundle args = new Bundle();
- args.putString(AppInfoBase.ARG_PACKAGE_NAME, pkg);
- args.putInt(AppInfoBase.ARG_PACKAGE_UID, uid);
-
- Intent intent = Utils.onBuildStartFragmentIntent(source, fragment.getName(),
- args, null, titleRes, null, false, sourceMetricsCategory);
- source.startActivityForResultAsUser(intent, request,
- new UserHandle(UserHandle.getUserId(uid)));
- }
-
- public static class MyAlertDialogFragment extends InstrumentedDialogFragment {
-
- private static final String ARG_ID = "id";
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.DIALOG_APP_INFO_ACTION;
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- int id = getArguments().getInt(ARG_ID);
- int errorCode = getArguments().getInt("moveError");
- Dialog dialog = ((AppInfoBase) getTargetFragment()).createDialog(id, errorCode);
- if (dialog == null) {
- throw new IllegalArgumentException("unknown id " + id);
- }
- return dialog;
- }
-
- public static AppInfoBase.MyAlertDialogFragment newInstance(int id, int errorCode) {
- AppInfoBase.MyAlertDialogFragment
- dialogFragment = new AppInfoBase.MyAlertDialogFragment();
- Bundle args = new Bundle();
- args.putInt(ARG_ID, id);
- args.putInt("moveError", errorCode);
- dialogFragment.setArguments(args);
- return dialogFragment;
- }
- }
-
- private void startListeningToPackageRemove() {
- if (mListeningToPackageRemove) {
- return;
- }
- mListeningToPackageRemove = true;
- final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
- getContext().registerReceiver(mPackageRemovedReceiver, filter);
- }
-
- private void stopListeningToPackageRemove() {
- if (!mListeningToPackageRemove) {
- return;
- }
- mListeningToPackageRemove = false;
- getContext().unregisterReceiver(mPackageRemovedReceiver);
- }
-
- private final BroadcastReceiver mPackageRemovedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String packageName = intent.getData().getSchemeSpecificPart();
- if (!mFinishing && (mAppEntry == null || mAppEntry.info == null
- || TextUtils.equals(mAppEntry.info.packageName, packageName))) {
- onPackageRemoved();
- }
- }
- };
-
-}
diff --git a/src/com/android/settings/applications/AppStoreUtil.java b/src/com/android/settings/applications/AppStoreUtil.java
index f9b95b0..13e5516 100644
--- a/src/com/android/settings/applications/AppStoreUtil.java
+++ b/src/com/android/settings/applications/AppStoreUtil.java
@@ -16,11 +16,9 @@
package com.android.settings.applications;
-
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
-import android.net.Uri;
import android.util.Log;
// This class provides methods that help dealing with app stores.
@@ -43,9 +41,6 @@
} catch (IllegalArgumentException e) {
Log.e(LOG_TAG, "Exception while retrieving the package installer of " + packageName, e);
}
- if (installerPackageName == null) {
- return null;
- }
return installerPackageName;
}
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index 2098bd6..f78459f 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -75,6 +75,7 @@
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
+import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.applications.appinfo.DrawOverlayDetails;
import com.android.settings.applications.appinfo.ExternalSourcesDetails;
import com.android.settings.applications.appinfo.PictureInPictureDetails;
diff --git a/src/com/android/settings/applications/InstalledAppDetailsTop.java b/src/com/android/settings/applications/InstalledAppDetailsTop.java
index 174a86a..8090de0 100644
--- a/src/com/android/settings/applications/InstalledAppDetailsTop.java
+++ b/src/com/android/settings/applications/InstalledAppDetailsTop.java
@@ -20,6 +20,7 @@
import android.util.FeatureFlagUtils;
import com.android.settings.SettingsActivity;
+import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.core.FeatureFlags;
public class InstalledAppDetailsTop extends SettingsActivity {
diff --git a/src/com/android/settings/applications/RecentAppsPreferenceController.java b/src/com/android/settings/applications/RecentAppsPreferenceController.java
index c613a7b..ee954ac 100644
--- a/src/com/android/settings/applications/RecentAppsPreferenceController.java
+++ b/src/com/android/settings/applications/RecentAppsPreferenceController.java
@@ -40,6 +40,7 @@
import com.android.settings.R;
import com.android.settings.Utils;
+import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.core.FeatureFlags;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.widget.AppPreference;
diff --git a/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceController.java b/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceController.java
new file mode 100644
index 0000000..b10d06c
--- /dev/null
+++ b/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceController.java
@@ -0,0 +1,318 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.PreferenceScreen;
+import android.util.Log;
+import android.webkit.IWebViewUpdateService;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.applications.ApplicationFeatureProvider;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.ActionButtonPreference;
+import com.android.settings.wrapper.DevicePolicyManagerWrapper;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.applications.AppUtils;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+public class AppActionButtonPreferenceController extends BasePreferenceController
+ implements AppInfoDashboardFragment.Callback {
+
+ private static final String TAG = "AppActionButtonControl";
+ private static final String KEY_ACTION_BUTTONS = "action_buttons";
+
+ @VisibleForTesting
+ ActionButtonPreference mActionButtons;
+ private final AppInfoDashboardFragment mParent;
+ private final String mPackageName;
+ private final HashSet<String> mHomePackages = new HashSet<>();
+ private final ApplicationFeatureProvider mApplicationFeatureProvider;
+
+ private int mUserId;
+ private DevicePolicyManagerWrapper mDpm;
+ private UserManager mUserManager;
+ private PackageManager mPm;
+
+ private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final boolean enabled = getResultCode() != Activity.RESULT_CANCELED;
+ Log.d(TAG, "Got broadcast response: Restart status for "
+ + mParent.getAppEntry().info.packageName + " " + enabled);
+ updateForceStopButton(enabled);
+ }
+ };
+
+ public AppActionButtonPreferenceController(Context context, AppInfoDashboardFragment parent,
+ String packageName) {
+ super(context, KEY_ACTION_BUTTONS);
+ mParent = parent;
+ mPackageName = packageName;
+ mUserId = UserHandle.myUserId();
+ mApplicationFeatureProvider = FeatureFactory.getFactory(context)
+ .getApplicationFeatureProvider(context);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mActionButtons = ((ActionButtonPreference) screen.findPreference(KEY_ACTION_BUTTONS))
+ .setButton2Text(R.string.force_stop)
+ .setButton2Positive(false)
+ .setButton2Enabled(false);
+ }
+
+ @Override
+ public void refreshUi() {
+ if (mPm == null) {
+ mPm = mContext.getPackageManager();
+ }
+ if (mDpm == null) {
+ mDpm = new DevicePolicyManagerWrapper(
+ (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE));
+ }
+ if (mUserManager == null) {
+ mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ }
+ final AppEntry appEntry = mParent.getAppEntry();
+ final PackageInfo packageInfo = mParent.getPackageInfo();
+
+ // Get list of "home" apps and trace through any meta-data references
+ final List<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
+ mPm.getHomeActivities(homeActivities);
+ mHomePackages.clear();
+ for (int i = 0; i< homeActivities.size(); i++) {
+ final ResolveInfo ri = homeActivities.get(i);
+ final String activityPkg = ri.activityInfo.packageName;
+ mHomePackages.add(activityPkg);
+
+ // Also make sure to include anything proxying for the home app
+ final Bundle metadata = ri.activityInfo.metaData;
+ if (metadata != null) {
+ final String metaPkg = metadata.getString(ActivityManager.META_HOME_ALTERNATE);
+ if (signaturesMatch(metaPkg, activityPkg)) {
+ mHomePackages.add(metaPkg);
+ }
+ }
+ }
+
+ checkForceStop(appEntry, packageInfo);
+ initUninstallButtons(appEntry, packageInfo);
+ }
+
+ @VisibleForTesting
+ void initUninstallButtons(AppEntry appEntry, PackageInfo packageInfo) {
+ final boolean isBundled = (appEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ boolean enabled;
+ if (isBundled) {
+ enabled = handleDisableable(appEntry, packageInfo);
+ } else {
+ enabled = initUninstallButtonForUserApp();
+ }
+ // If this is a device admin, it can't be uninstalled or disabled.
+ // We do this here so the text of the button is still set correctly.
+ if (isBundled && mDpm.packageHasActiveAdmins(packageInfo.packageName)) {
+ enabled = false;
+ }
+
+ // We don't allow uninstalling DO/PO on *any* users, because if it's a system app,
+ // "uninstall" is actually "downgrade to the system version + disable", and "downgrade"
+ // will clear data on all users.
+ if (Utils.isProfileOrDeviceOwner(mUserManager, mDpm, packageInfo.packageName)) {
+ enabled = false;
+ }
+
+ // Don't allow uninstalling the device provisioning package.
+ if (Utils.isDeviceProvisioningPackage(mContext.getResources(), appEntry.info.packageName)) {
+ enabled = false;
+ }
+
+ // If the uninstall intent is already queued, disable the uninstall button
+ if (mDpm.isUninstallInQueue(mPackageName)) {
+ enabled = false;
+ }
+
+ // Home apps need special handling. Bundled ones we don't risk downgrading
+ // because that can interfere with home-key resolution. Furthermore, we
+ // can't allow uninstallation of the only home app, and we don't want to
+ // allow uninstallation of an explicitly preferred one -- the user can go
+ // to Home settings and pick a different one, after which we'll permit
+ // uninstallation of the now-not-default one.
+ if (enabled && mHomePackages.contains(packageInfo.packageName)) {
+ if (isBundled) {
+ enabled = false;
+ } else {
+ ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
+ ComponentName currentDefaultHome = mPm.getHomeActivities(homeActivities);
+ if (currentDefaultHome == null) {
+ // No preferred default, so permit uninstall only when
+ // there is more than one candidate
+ enabled = (mHomePackages.size() > 1);
+ } else {
+ // There is an explicit default home app -- forbid uninstall of
+ // that one, but permit it for installed-but-inactive ones.
+ enabled = !packageInfo.packageName.equals(currentDefaultHome.getPackageName());
+ }
+ }
+ }
+
+ if (RestrictedLockUtils.hasBaseUserRestriction(
+ mContext, UserManager.DISALLOW_APPS_CONTROL, mUserId)) {
+ enabled = false;
+ }
+
+ try {
+ final IWebViewUpdateService webviewUpdateService =
+ IWebViewUpdateService.Stub.asInterface(
+ ServiceManager.getService("webviewupdate"));
+ if (webviewUpdateService.isFallbackPackage(appEntry.info.packageName)) {
+ enabled = false;
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+
+ mActionButtons.setButton1Enabled(enabled);
+ if (enabled) {
+ // Register listener
+ mActionButtons.setButton1OnClickListener(v -> mParent.handleUninstallButtonClick());
+ }
+ }
+
+ @VisibleForTesting
+ boolean initUninstallButtonForUserApp() {
+ boolean enabled = true;
+ final PackageInfo packageInfo = mParent.getPackageInfo();
+ if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) == 0
+ && mUserManager.getUsers().size() >= 2) {
+ // When we have multiple users, there is a separate menu
+ // to uninstall for all users.
+ enabled = false;
+ } else if (AppUtils.isInstant(packageInfo.applicationInfo)) {
+ enabled = false;
+ mActionButtons.setButton1Visible(false);
+ }
+ mActionButtons.setButton1Text(R.string.uninstall_text).setButton1Positive(false);
+ return enabled;
+ }
+
+ @VisibleForTesting
+ boolean handleDisableable(AppEntry appEntry, PackageInfo packageInfo) {
+ boolean disableable = false;
+ // Try to prevent the user from bricking their phone
+ // by not allowing disabling of apps signed with the
+ // system cert and any launcher app in the system.
+ if (mHomePackages.contains(appEntry.info.packageName)
+ || Utils.isSystemPackage(mContext.getResources(), mPm, packageInfo)) {
+ // Disable button for core system applications.
+ mActionButtons
+ .setButton1Text(R.string.disable_text)
+ .setButton1Positive(false);
+ } else if (appEntry.info.enabled && appEntry.info.enabledSetting
+ != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+ mActionButtons
+ .setButton1Text(R.string.disable_text)
+ .setButton1Positive(false);
+ disableable = !mApplicationFeatureProvider.getKeepEnabledPackages()
+ .contains(appEntry.info.packageName);
+ } else {
+ mActionButtons
+ .setButton1Text(R.string.enable_text)
+ .setButton1Positive(true);
+ disableable = true;
+ }
+
+ return disableable;
+ }
+
+ private void updateForceStopButton(boolean enabled) {
+ final boolean disallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction(
+ mContext, UserManager.DISALLOW_APPS_CONTROL, mUserId);
+ mActionButtons
+ .setButton2Enabled(disallowedBySystem ? false : enabled)
+ .setButton2OnClickListener(
+ disallowedBySystem ? null : v -> mParent.handleForceStopButtonClick());
+ }
+
+ void checkForceStop(AppEntry appEntry, PackageInfo packageInfo) {
+ if (mDpm.packageHasActiveAdmins(packageInfo.packageName)) {
+ // User can't force stop device admin.
+ Log.w(TAG, "User can't force stop device admin");
+ updateForceStopButton(false);
+ } else if (AppUtils.isInstant(packageInfo.applicationInfo)) {
+ updateForceStopButton(false);
+ mActionButtons.setButton2Visible(false);
+ } else if ((appEntry.info.flags & ApplicationInfo.FLAG_STOPPED) == 0) {
+ // If the app isn't explicitly stopped, then always show the
+ // force stop button.
+ Log.w(TAG, "App is not explicitly stopped");
+ updateForceStopButton(true);
+ } else {
+ final Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
+ Uri.fromParts("package", appEntry.info.packageName, null));
+ intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { appEntry.info.packageName });
+ intent.putExtra(Intent.EXTRA_UID, appEntry.info.uid);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(appEntry.info.uid));
+ Log.d(TAG, "Sending broadcast to query restart status for "
+ + appEntry.info.packageName);
+ mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
+ mCheckKillProcessesReceiver, null, Activity.RESULT_CANCELED, null, null);
+ }
+ }
+
+ private boolean signaturesMatch(String pkg1, String pkg2) {
+ if (pkg1 != null && pkg2 != null) {
+ try {
+ return mPm.checkSignatures(pkg1, pkg2) >= PackageManager.SIGNATURE_MATCH;
+ } catch (Exception e) {
+ // e.g. named alternate package not found during lookup;
+ // this is an expected case sometimes
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java
index d341d53..ffe2bf3 100644
--- a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java
@@ -17,7 +17,6 @@
package com.android.settings.applications.appinfo;
import android.app.LoaderManager;
-import android.app.slice.Slice;
import android.content.Context;
import android.content.Loader;
import android.content.pm.PackageInfo;
@@ -33,7 +32,6 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
import com.android.settings.fuelgauge.BatteryEntry;
@@ -82,11 +80,6 @@
}
@Override
- public Slice getSettingSlice() {
- return null;
- }
-
- @Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
diff --git a/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceController.java b/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceController.java
index 61f3e46..669bc5a 100644
--- a/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceController.java
@@ -34,7 +34,6 @@
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.datausage.AppDataUsage;
import com.android.settings.datausage.DataUsageList;
import com.android.settings.datausage.DataUsageUtils;
diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
new file mode 100755
index 0000000..57e2b0c
--- /dev/null
+++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
@@ -0,0 +1,831 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.DeviceAdminAdd;
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.Utils;
+import com.android.settings.applications.LayoutPreference;
+import com.android.settings.applications.manageapplications.ManageApplications;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.widget.EntityHeaderController;
+import com.android.settings.widget.PreferenceCategoryController;
+import com.android.settings.wrapper.DevicePolicyManagerWrapper;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.applications.AppUtils;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Dashboard fragment to display application information from Settings. This activity presents
+ * extended information associated with a package like code, data, total size, permissions
+ * used by the application and also the set of default launchable activities.
+ * For system applications, an option to clear user data is displayed only if data size is > 0.
+ * System applications that do not want clear user data do not have this option.
+ * For non-system applications, there is no option to clear data. Instead there is an option to
+ * uninstall the application.
+ */
+public class AppInfoDashboardFragment extends DashboardFragment
+ implements ApplicationsState.Callbacks {
+
+ private static final String TAG = "AppInfoDashboard";
+
+ // Menu identifiers
+ private static final int UNINSTALL_ALL_USERS_MENU = 1;
+ private static final int UNINSTALL_UPDATES = 2;
+
+ // Result code identifiers
+ @VisibleForTesting
+ static final int REQUEST_UNINSTALL = 0;
+ private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1;
+
+ static final int SUB_INFO_FRAGMENT = 1;
+
+ static final int LOADER_CHART_DATA = 2;
+ static final int LOADER_STORAGE = 3;
+ static final int LOADER_BATTERY = 4;
+
+ // Dialog identifiers used in showDialog
+ private static final int DLG_BASE = 0;
+ private static final int DLG_FORCE_STOP = DLG_BASE + 1;
+ private static final int DLG_DISABLE = DLG_BASE + 2;
+ private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3;
+
+ private static final String KEY_HEADER = "header_view";
+ private static final String KEY_ADVANCED_APP_INFO_CATEGORY = "advanced_app_info";
+
+ public static final String ARG_PACKAGE_NAME = "package";
+ public static final String ARG_PACKAGE_UID = "uid";
+
+ private static final boolean localLOGV = false;
+
+ private EnforcedAdmin mAppsControlDisallowedAdmin;
+ private boolean mAppsControlDisallowedBySystem;
+
+ private ApplicationsState mState;
+ private ApplicationsState.Session mSession;
+ private ApplicationsState.AppEntry mAppEntry;
+ private PackageInfo mPackageInfo;
+ private int mUserId;
+ private String mPackageName;
+
+ private DevicePolicyManagerWrapper mDpm;
+ private UserManager mUserManager;
+ private PackageManager mPm;
+
+ private boolean mFinishing;
+ private boolean mListeningToPackageRemove;
+
+
+ private boolean mInitialized;
+ private boolean mShowUninstalled;
+ private LayoutPreference mHeader;
+ private boolean mUpdatedSysApp = false;
+ private boolean mDisableAfterUninstall;
+
+ private List<Callback> mCallbacks = new ArrayList<>();
+
+ private InstantAppButtonsPreferenceController mInstantAppButtonPreferenceController;
+ private AppActionButtonPreferenceController mAppActionButtonPreferenceController;
+
+ /**
+ * Callback to invoke when app info has been changed.
+ */
+ public interface Callback {
+ void refreshUi();
+ }
+
+ private boolean isDisabledUntilUsed() {
+ return mAppEntry.info.enabledSetting
+ == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+ }
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mFinishing = false;
+ final Activity activity = getActivity();
+ mDpm = new DevicePolicyManagerWrapper(
+ (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE));
+ mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE);
+ mPm = activity.getPackageManager();
+
+ retrieveAppEntry();
+ startListeningToPackageRemove();
+
+ if (!ensurePackageInfoAvailable(activity)) {
+ return;
+ }
+
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.APPLICATIONS_INSTALLED_APP_DETAILS;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mAppsControlDisallowedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(getActivity(),
+ UserManager.DISALLOW_APPS_CONTROL, mUserId);
+ mAppsControlDisallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction(getActivity(),
+ UserManager.DISALLOW_APPS_CONTROL, mUserId);
+
+ if (!refreshUi()) {
+ setIntentAndFinish(true, true);
+ }
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.app_info_settings;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
+ final String packageName = getPackageName();
+ final List<AbstractPreferenceController> controllers = new ArrayList<>();
+ final Lifecycle lifecycle = getLifecycle();
+
+ // The following are controllers for preferences that needs to refresh the preference state
+ // when app state changes.
+ controllers.add(new AppStoragePreferenceController(context, this, lifecycle));
+ controllers.add(new AppDataUsagePreferenceController(context, this, lifecycle));
+ controllers.add(new AppNotificationPreferenceController(context, this));
+ controllers.add(new AppOpenByDefaultPreferenceController(context, this));
+ controllers.add(new AppPermissionPreferenceController(context, this, packageName));
+ controllers.add(new AppVersionPreferenceController(context, this));
+ controllers.add(new InstantAppDomainsPreferenceController(context, this));
+ final AppInstallerInfoPreferenceController appInstallerInfoPreferenceController =
+ new AppInstallerInfoPreferenceController(context, this, packageName);
+ controllers.add(appInstallerInfoPreferenceController);
+ mAppActionButtonPreferenceController =
+ new AppActionButtonPreferenceController(context, this, packageName);
+ controllers.add(mAppActionButtonPreferenceController);
+
+ for (AbstractPreferenceController controller : controllers) {
+ mCallbacks.add((Callback) controller);
+ }
+
+ // The following are controllers for preferences that don't need to refresh the preference
+ // state when app state changes.
+ mInstantAppButtonPreferenceController =
+ new InstantAppButtonsPreferenceController(context, this, packageName);
+ controllers.add(mInstantAppButtonPreferenceController);
+ controllers.add(new AppBatteryPreferenceController(context, this, packageName, lifecycle));
+ controllers.add(new AppMemoryPreferenceController(context, this, lifecycle));
+ controllers.add(new DefaultHomeShortcutPreferenceController(context, packageName));
+ controllers.add(new DefaultBrowserShortcutPreferenceController(context, packageName));
+ controllers.add(new DefaultPhoneShortcutPreferenceController(context, packageName));
+ controllers.add(new DefaultEmergencyShortcutPreferenceController(context, packageName));
+ controllers.add(new DefaultSmsShortcutPreferenceController(context, packageName));
+
+ final List<AbstractPreferenceController> advancedAppInfoControllers = new ArrayList<>();
+ advancedAppInfoControllers.add(new DrawOverlayDetailPreferenceController(context, this));
+ advancedAppInfoControllers.add(new WriteSystemSettingsPreferenceController(context, this));
+ advancedAppInfoControllers.add(
+ new PictureInPictureDetailPreferenceController(context, this, packageName));
+ advancedAppInfoControllers.add(
+ new ExternalSourceDetailPreferenceController(context, this, packageName));
+ controllers.addAll(advancedAppInfoControllers);
+ controllers.add(new PreferenceCategoryController(
+ context, KEY_ADVANCED_APP_INFO_CATEGORY, advancedAppInfoControllers));
+
+ controllers.add(new AppInstallerPreferenceCategoryController(
+ context, Arrays.asList(appInstallerInfoPreferenceController)));
+
+ return controllers;
+ }
+
+ ApplicationsState.AppEntry getAppEntry() {
+ if (mAppEntry == null) {
+ retrieveAppEntry();
+ }
+ return mAppEntry;
+ }
+
+ PackageInfo getPackageInfo() {
+ if (mAppEntry == null) {
+ retrieveAppEntry();
+ }
+ return mPackageInfo;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ if (mFinishing) {
+ return;
+ }
+ final Activity activity = getActivity();
+ mHeader = (LayoutPreference) findPreference(KEY_HEADER);
+ EntityHeaderController.newInstance(activity, this, mHeader.findViewById(R.id.entity_header))
+ .setRecyclerView(getListView(), getLifecycle())
+ .setPackageName(mPackageName)
+ .setHasAppInfoLink(false)
+ .setButtonActions(EntityHeaderController.ActionType.ACTION_APP_PREFERENCE,
+ EntityHeaderController.ActionType.ACTION_NONE)
+ .styleActionBar(activity)
+ .bindHeaderButtons();
+
+ }
+
+ @Override
+ public void onPackageSizeChanged(String packageName) {
+ if (!TextUtils.equals(packageName, mPackageName)) {
+ Log.d(TAG, "Package change irrelevant, skipping");
+ return;
+ }
+ refreshUi();
+ }
+
+ /**
+ * Ensures the {@link PackageInfo} is available to proceed. If it's not available, the fragment
+ * will finish.
+ *
+ * @return true if packageInfo is available.
+ */
+ @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+ boolean ensurePackageInfoAvailable(Activity activity) {
+ if (mPackageInfo == null) {
+ mFinishing = true;
+ Log.w(TAG, "Package info not available. Is this package already uninstalled?");
+ activity.finishAndRemoveTask();
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ menu.add(0, UNINSTALL_UPDATES, 0, R.string.app_factory_reset)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ menu.add(0, UNINSTALL_ALL_USERS_MENU, 1, R.string.uninstall_all_users_text)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ if (mFinishing) {
+ return;
+ }
+ menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(shouldShowUninstallForAll(mAppEntry));
+ mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
+ final MenuItem uninstallUpdatesItem = menu.findItem(UNINSTALL_UPDATES);
+ uninstallUpdatesItem.setVisible(mUpdatedSysApp && !mAppsControlDisallowedBySystem);
+ if (uninstallUpdatesItem.isVisible()) {
+ RestrictedLockUtils.setMenuItemAsDisabledByAdmin(getActivity(),
+ uninstallUpdatesItem, mAppsControlDisallowedAdmin);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case UNINSTALL_ALL_USERS_MENU:
+ uninstallPkg(mAppEntry.info.packageName, true, false);
+ return true;
+ case UNINSTALL_UPDATES:
+ uninstallPkg(mAppEntry.info.packageName, false, false);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case REQUEST_UNINSTALL:
+ // Refresh option menu
+ getActivity().invalidateOptionsMenu();
+
+ if (mDisableAfterUninstall) {
+ mDisableAfterUninstall = false;
+ new DisableChanger(this, mAppEntry.info,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
+ .execute((Object) null);
+ }
+ // continue with following operations
+ case REQUEST_REMOVE_DEVICE_ADMIN:
+ if (!refreshUi()) {
+ setIntentAndFinish(true, true);
+ } else {
+ startListeningToPackageRemove();
+ }
+ break;
+ }
+ }
+
+ // Utility method to set application label and icon.
+ private void setAppLabelAndIcon(PackageInfo pkgInfo) {
+ final View appSnippet = mHeader.findViewById(R.id.entity_header);
+ mState.ensureIcon(mAppEntry);
+ final Activity activity = getActivity();
+ final boolean isInstantApp = AppUtils.isInstant(mPackageInfo.applicationInfo);
+ final CharSequence summary =
+ isInstantApp ? null : getString(Utils.getInstallationStatus(mAppEntry.info));
+ EntityHeaderController.newInstance(activity, this, appSnippet)
+ .setLabel(mAppEntry)
+ .setIcon(mAppEntry)
+ .setSummary(summary)
+ .setIsInstantApp(isInstantApp)
+ .done(activity, false /* rebindActions */);
+ }
+
+ @VisibleForTesting
+ boolean shouldShowUninstallForAll(AppEntry appEntry) {
+ boolean showIt = true;
+ if (mUpdatedSysApp) {
+ showIt = false;
+ } else if (appEntry == null) {
+ showIt = false;
+ } else if ((appEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ showIt = false;
+ } else if (mPackageInfo == null || mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
+ showIt = false;
+ } else if (UserHandle.myUserId() != 0) {
+ showIt = false;
+ } else if (mUserManager.getUsers().size() < 2) {
+ showIt = false;
+ } else if (getNumberOfUserWithPackageInstalled(mPackageName) < 2
+ && (appEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
+ showIt = false;
+ } else if (AppUtils.isInstant(appEntry.info)) {
+ showIt = false;
+ }
+ return showIt;
+ }
+
+ @VisibleForTesting
+ boolean refreshUi() {
+ retrieveAppEntry();
+ if (mAppEntry == null) {
+ return false; // onCreate must have failed, make sure to exit
+ }
+
+ if (mPackageInfo == null) {
+ return false; // onCreate must have failed, make sure to exit
+ }
+
+
+ setAppLabelAndIcon(mPackageInfo);
+
+ // Update the preference summaries.
+ final Activity context = getActivity();
+ for (Callback callback : mCallbacks) {
+ callback.refreshUi();
+ }
+
+ if (!mInitialized) {
+ // First time init: are we displaying an uninstalled app?
+ mInitialized = true;
+ mShowUninstalled = (mAppEntry.info.flags&ApplicationInfo.FLAG_INSTALLED) == 0;
+ } else {
+ // All other times: if the app no longer exists then we want
+ // to go away.
+ try {
+ final ApplicationInfo ainfo = context.getPackageManager().getApplicationInfo(
+ mAppEntry.info.packageName,
+ PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_ANY_USER);
+ if (!mShowUninstalled) {
+ // If we did not start out with the app uninstalled, then
+ // it transitioning to the uninstalled state for the current
+ // user means we should go away as well.
+ return (ainfo.flags&ApplicationInfo.FLAG_INSTALLED) != 0;
+ }
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @VisibleForTesting
+ AlertDialog createDialog(int id, int errorCode) {
+ switch (id) {
+ case DLG_DISABLE:
+ return new AlertDialog.Builder(getActivity())
+ .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
+ .setPositiveButton(R.string.app_disable_dlg_positive,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Disable the app
+ mMetricsFeatureProvider.action(getContext(),
+ MetricsEvent.ACTION_SETTINGS_DISABLE_APP);
+ new DisableChanger(AppInfoDashboardFragment.this, mAppEntry.info,
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
+ .execute((Object)null);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ case DLG_SPECIAL_DISABLE:
+ return new AlertDialog.Builder(getActivity())
+ .setMessage(getActivity().getText(R.string.app_disable_dlg_text))
+ .setPositiveButton(R.string.app_disable_dlg_positive,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Disable the app and ask for uninstall
+ mMetricsFeatureProvider.action(getContext(),
+ MetricsEvent.ACTION_SETTINGS_DISABLE_APP);
+ uninstallPkg(mAppEntry.info.packageName,
+ false, true);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ case DLG_FORCE_STOP:
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(getActivity().getText(R.string.force_stop_dlg_title))
+ .setMessage(getActivity().getText(R.string.force_stop_dlg_text))
+ .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Force stop
+ forceStopPackage(mAppEntry.info.packageName);
+ }
+ })
+ .setNegativeButton(R.string.dlg_cancel, null)
+ .create();
+ }
+ return mInstantAppButtonPreferenceController.createDialog(id);
+ }
+
+ private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) {
+ stopListeningToPackageRemove();
+ // Create new intent to launch Uninstaller activity
+ final Uri packageURI = Uri.parse("package:"+packageName);
+ final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
+ uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers);
+ mMetricsFeatureProvider.action(
+ getContext(), MetricsEvent.ACTION_SETTINGS_UNINSTALL_APP);
+ startActivityForResult(uninstallIntent, REQUEST_UNINSTALL);
+ mDisableAfterUninstall = andDisable;
+ }
+
+ private void forceStopPackage(String pkgName) {
+ mMetricsFeatureProvider.action(getContext(), MetricsEvent.ACTION_APP_FORCE_STOP, pkgName);
+ final ActivityManager am = (ActivityManager) getActivity().getSystemService(
+ Context.ACTIVITY_SERVICE);
+ Log.d(TAG, "Stopping package " + pkgName);
+ am.forceStopPackage(pkgName);
+ final int userId = UserHandle.getUserId(mAppEntry.info.uid);
+ mState.invalidatePackage(pkgName, userId);
+ final AppEntry newEnt = mState.getEntry(pkgName, userId);
+ if (newEnt != null) {
+ mAppEntry = newEnt;
+ }
+ mAppActionButtonPreferenceController.checkForceStop(mAppEntry, mPackageInfo);
+ }
+
+ public static void startAppInfoFragment(Class<?> fragment, int title,
+ SettingsPreferenceFragment caller, AppEntry appEntry) {
+ // start new fragment to display extended information
+ final Bundle args = new Bundle();
+ args.putString(ARG_PACKAGE_NAME, appEntry.info.packageName);
+ args.putInt(ARG_PACKAGE_UID, appEntry.info.uid);
+
+ final SettingsActivity sa = (SettingsActivity) caller.getActivity();
+ sa.startPreferencePanel(caller, fragment.getName(), args, title, null, caller,
+ SUB_INFO_FRAGMENT);
+ }
+
+ void handleUninstallButtonClick() {
+ if (mAppEntry == null) {
+ setIntentAndFinish(true, true);
+ return;
+ }
+ final String packageName = mAppEntry.info.packageName;
+ if (mDpm.packageHasActiveAdmins(mPackageInfo.packageName)) {
+ stopListeningToPackageRemove();
+ final Activity activity = getActivity();
+ final Intent uninstallDAIntent = new Intent(activity, DeviceAdminAdd.class);
+ uninstallDAIntent.putExtra(DeviceAdminAdd.EXTRA_DEVICE_ADMIN_PACKAGE_NAME,
+ mPackageName);
+ mMetricsFeatureProvider.action(
+ activity, MetricsEvent.ACTION_SETTINGS_UNINSTALL_DEVICE_ADMIN);
+ activity.startActivityForResult(uninstallDAIntent, REQUEST_REMOVE_DEVICE_ADMIN);
+ return;
+ }
+ final EnforcedAdmin admin = RestrictedLockUtils.checkIfUninstallBlocked(getActivity(),
+ packageName, mUserId);
+ final boolean uninstallBlockedBySystem = mAppsControlDisallowedBySystem ||
+ RestrictedLockUtils.hasBaseUserRestriction(getActivity(), packageName, mUserId);
+ if (admin != null && !uninstallBlockedBySystem) {
+ RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(), admin);
+ } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ if (mAppEntry.info.enabled && !isDisabledUntilUsed()) {
+ // If the system app has an update and this is the only user on the device,
+ // then offer to downgrade the app, otherwise only offer to disable the
+ // app for this user.
+ if (mUpdatedSysApp && isSingleUser()) {
+ showDialogInner(DLG_SPECIAL_DISABLE, 0);
+ } else {
+ showDialogInner(DLG_DISABLE, 0);
+ }
+ } else {
+ mMetricsFeatureProvider.action(
+ getActivity(),
+ MetricsEvent.ACTION_SETTINGS_ENABLE_APP);
+ new DisableChanger(this, mAppEntry.info,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
+ .execute((Object) null);
+ }
+ } else if ((mAppEntry.info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
+ uninstallPkg(packageName, true, false);
+ } else {
+ uninstallPkg(packageName, false, false);
+ }
+ }
+
+ void handleForceStopButtonClick() {
+ if (mAppEntry == null) {
+ setIntentAndFinish(true, true);
+ return;
+ }
+ if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) {
+ RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
+ getActivity(), mAppsControlDisallowedAdmin);
+ } else {
+ showDialogInner(DLG_FORCE_STOP, 0);
+ //forceStopPackage(mAppInfo.packageName);
+ }
+ }
+
+ /** Returns whether there is only one user on this device, not including the system-only user */
+ private boolean isSingleUser() {
+ final int userCount = mUserManager.getUserCount();
+ return userCount == 1 || (mUserManager.isSplitSystemUser() && userCount == 2);
+ }
+
+ private void onPackageRemoved() {
+ getActivity().finishActivity(SUB_INFO_FRAGMENT);
+ getActivity().finishAndRemoveTask();
+ }
+
+ @VisibleForTesting
+ int getNumberOfUserWithPackageInstalled(String packageName) {
+ final List<UserInfo> userInfos = mUserManager.getUsers(true);
+ int count = 0;
+
+ for (final UserInfo userInfo : userInfos) {
+ try {
+ // Use this API to check whether user has this package
+ final ApplicationInfo info = mPm.getApplicationInfoAsUser(
+ packageName, PackageManager.GET_META_DATA, userInfo.id);
+ if ((info.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
+ count++;
+ }
+ } catch(NameNotFoundException e) {
+ Log.e(TAG, "Package: " + packageName + " not found for user: " + userInfo.id);
+ }
+ }
+
+ return count;
+ }
+
+ private static class DisableChanger extends AsyncTask<Object, Object, Object> {
+ final PackageManager mPm;
+ final WeakReference<AppInfoDashboardFragment> mActivity;
+ final ApplicationInfo mInfo;
+ final int mState;
+
+ DisableChanger(AppInfoDashboardFragment activity, ApplicationInfo info, int state) {
+ mPm = activity.mPm;
+ mActivity = new WeakReference<AppInfoDashboardFragment>(activity);
+ mInfo = info;
+ mState = state;
+ }
+
+ @Override
+ protected Object doInBackground(Object... params) {
+ mPm.setApplicationEnabledSetting(mInfo.packageName, mState, 0);
+ return null;
+ }
+ }
+
+ private String getPackageName() {
+ if (mPackageName != null) {
+ return mPackageName;
+ }
+ final Bundle args = getArguments();
+ mPackageName = (args != null) ? args.getString(ARG_PACKAGE_NAME) : null;
+ if (mPackageName == null) {
+ final Intent intent = (args == null) ?
+ getActivity().getIntent() : (Intent) args.getParcelable("intent");
+ if (intent != null) {
+ mPackageName = intent.getData().getSchemeSpecificPart();
+ }
+ }
+ return mPackageName;
+ }
+
+ private void retrieveAppEntry() {
+ final Activity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+ if (mState == null) {
+ mState = ApplicationsState.getInstance(activity.getApplication());
+ mSession = mState.newSession(this, getLifecycle());
+ }
+ mUserId = UserHandle.myUserId();
+ mAppEntry = mState.getEntry(getPackageName(), UserHandle.myUserId());
+ if (mAppEntry != null) {
+ // Get application info again to refresh changed properties of application
+ try {
+ mPackageInfo = activity.getPackageManager().getPackageInfo(
+ mAppEntry.info.packageName,
+ PackageManager.MATCH_DISABLED_COMPONENTS |
+ PackageManager.MATCH_ANY_USER |
+ PackageManager.GET_SIGNATURES |
+ PackageManager.GET_PERMISSIONS);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Exception when retrieving package:" + mAppEntry.info.packageName, e);
+ }
+ } else {
+ Log.w(TAG, "Missing AppEntry; maybe reinstalling?");
+ mPackageInfo = null;
+ }
+ }
+
+ private void setIntentAndFinish(boolean finish, boolean appChanged) {
+ if (localLOGV) Log.i(TAG, "appChanged="+appChanged);
+ final Intent intent = new Intent();
+ intent.putExtra(ManageApplications.APP_CHG, appChanged);
+ final SettingsActivity sa = (SettingsActivity)getActivity();
+ sa.finishPreferencePanel(this, Activity.RESULT_OK, intent);
+ mFinishing = true;
+ }
+
+ void showDialogInner(int id, int moveErrorCode) {
+ final DialogFragment newFragment = MyAlertDialogFragment.newInstance(id, moveErrorCode);
+ newFragment.setTargetFragment(this, 0);
+ newFragment.show(getFragmentManager(), "dialog " + id);
+ }
+
+ @Override
+ public void onRunningStateChanged(boolean running) {
+ // No op.
+ }
+
+ @Override
+ public void onRebuildComplete(ArrayList<AppEntry> apps) {
+ // No op.
+ }
+
+ @Override
+ public void onPackageIconChanged() {
+ // No op.
+ }
+
+ @Override
+ public void onAllSizesComputed() {
+ // No op.
+ }
+
+ @Override
+ public void onLauncherInfoChanged() {
+ // No op.
+ }
+
+ @Override
+ public void onLoadEntriesCompleted() {
+ // No op.
+ }
+
+ @Override
+ public void onPackageListChanged() {
+ if (!refreshUi()) {
+ setIntentAndFinish(true, true);
+ }
+ }
+
+ public static class MyAlertDialogFragment extends InstrumentedDialogFragment {
+
+ private static final String ARG_ID = "id";
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.DIALOG_APP_INFO_ACTION;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final int id = getArguments().getInt(ARG_ID);
+ final int errorCode = getArguments().getInt("moveError");
+ final Dialog dialog =
+ ((AppInfoDashboardFragment) getTargetFragment()).createDialog(id, errorCode);
+ if (dialog == null) {
+ throw new IllegalArgumentException("unknown id " + id);
+ }
+ return dialog;
+ }
+
+ public static MyAlertDialogFragment newInstance(int id, int errorCode) {
+ final MyAlertDialogFragment dialogFragment = new MyAlertDialogFragment();
+ final Bundle args = new Bundle();
+ args.putInt(ARG_ID, id);
+ args.putInt("moveError", errorCode);
+ dialogFragment.setArguments(args);
+ return dialogFragment;
+ }
+ }
+
+ private void startListeningToPackageRemove() {
+ if (mListeningToPackageRemove) {
+ return;
+ }
+ mListeningToPackageRemove = true;
+ final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ getContext().registerReceiver(mPackageRemovedReceiver, filter);
+ }
+
+ private void stopListeningToPackageRemove() {
+ if (!mListeningToPackageRemove) {
+ return;
+ }
+ mListeningToPackageRemove = false;
+ getContext().unregisterReceiver(mPackageRemovedReceiver);
+ }
+
+ private final BroadcastReceiver mPackageRemovedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String packageName = intent.getData().getSchemeSpecificPart();
+ if (!mFinishing && (mAppEntry == null || mAppEntry.info == null
+ || TextUtils.equals(mAppEntry.info.packageName, packageName))) {
+ onPackageRemoved();
+ }
+ }
+ };
+
+}
diff --git a/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBase.java b/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBase.java
index 0d6c038..105a01e 100644
--- a/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBase.java
+++ b/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBase.java
@@ -16,14 +16,12 @@
package com.android.settings.applications.appinfo;
-import android.app.slice.Slice;
import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;
import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.core.BasePreferenceController;
/*
@@ -51,11 +49,6 @@
}
@Override
- public Slice getSettingSlice() {
- return null;
- }
-
- @Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
diff --git a/src/com/android/settings/applications/appinfo/AppInstallerInfoPreferenceController.java b/src/com/android/settings/applications/appinfo/AppInstallerInfoPreferenceController.java
new file mode 100644
index 0000000..1fdc690
--- /dev/null
+++ b/src/com/android/settings/applications/appinfo/AppInstallerInfoPreferenceController.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserManager;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.applications.AppStoreUtil;
+import com.android.settingslib.applications.AppUtils;
+
+public class AppInstallerInfoPreferenceController extends AppInfoPreferenceControllerBase {
+
+ private static final String KEY_APP_INSTALLER_INFO = "app_info_store";
+
+ private final String mPackageName;
+ private final String mInstallerPackage;
+ private final CharSequence mInstallerLabel;
+
+ public AppInstallerInfoPreferenceController(Context context, AppInfoDashboardFragment parent,
+ String packageName) {
+ super(context, parent, KEY_APP_INSTALLER_INFO);
+ mPackageName = packageName;
+ mInstallerPackage = AppStoreUtil.getInstallerPackageName(mContext, mPackageName);
+ mInstallerLabel = Utils.getApplicationLabel(mContext, mInstallerPackage);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ if (UserManager.get(mContext).isManagedProfile()) {
+ return DISABLED_FOR_USER;
+ }
+ return mInstallerLabel!= null ? AVAILABLE : DISABLED_FOR_USER;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ final int detailsStringId = AppUtils.isInstant(mParent.getPackageInfo().applicationInfo)
+ ? R.string.instant_app_details_summary
+ : R.string.app_install_details_summary;
+ preference.setSummary(mContext.getString(detailsStringId, mInstallerLabel));
+
+ Intent intent = AppStoreUtil.getAppStoreLink(mContext, mInstallerPackage, mPackageName);
+ if (intent != null) {
+ preference.setIntent(intent);
+ } else {
+ preference.setEnabled(false);
+ }
+ }
+
+}
diff --git a/src/com/android/settings/applications/appinfo/AppInstallerPreferenceCategoryController.java b/src/com/android/settings/applications/appinfo/AppInstallerPreferenceCategoryController.java
new file mode 100644
index 0000000..0e6ffe8
--- /dev/null
+++ b/src/com/android/settings/applications/appinfo/AppInstallerPreferenceCategoryController.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import android.content.Context;
+
+import com.android.settings.widget.PreferenceCategoryController;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import java.util.List;
+
+public class AppInstallerPreferenceCategoryController extends PreferenceCategoryController {
+
+ private static final String KEY_APP_INSTALLER_INFO_CATEGORY = "app_installer";
+
+ public AppInstallerPreferenceCategoryController(Context context,
+ List<AbstractPreferenceController> childrenControllers) {
+ super(context, KEY_APP_INSTALLER_INFO_CATEGORY, childrenControllers);
+ }
+
+}
diff --git a/src/com/android/settings/applications/appinfo/AppMemoryPreferenceController.java b/src/com/android/settings/applications/appinfo/AppMemoryPreferenceController.java
index 2a20f80..7b497a9 100644
--- a/src/com/android/settings/applications/appinfo/AppMemoryPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppMemoryPreferenceController.java
@@ -17,7 +17,6 @@
package com.android.settings.applications.appinfo;
import android.app.Activity;
-import android.app.slice.Slice;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.os.AsyncTask;
@@ -27,7 +26,6 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.applications.ProcStatsData;
import com.android.settings.applications.ProcStatsEntry;
import com.android.settings.applications.ProcStatsPackageEntry;
@@ -111,11 +109,6 @@
}
@Override
- public Slice getSettingSlice() {
- return null;
- }
-
- @Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
diff --git a/src/com/android/settings/applications/appinfo/AppNotificationPreferenceController.java b/src/com/android/settings/applications/appinfo/AppNotificationPreferenceController.java
index 7eef370..1f19504 100644
--- a/src/com/android/settings/applications/appinfo/AppNotificationPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppNotificationPreferenceController.java
@@ -20,7 +20,6 @@
import android.support.v7.preference.Preference;
import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.notification.AppNotificationSettings;
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.applications.ApplicationsState;
diff --git a/src/com/android/settings/applications/appinfo/AppOpenByDefaultPreferenceController.java b/src/com/android/settings/applications/appinfo/AppOpenByDefaultPreferenceController.java
index a56e3fb..3f20381 100644
--- a/src/com/android/settings/applications/appinfo/AppOpenByDefaultPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppOpenByDefaultPreferenceController.java
@@ -26,7 +26,6 @@
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.applications.AppLaunchSettings;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
diff --git a/src/com/android/settings/applications/appinfo/AppPermissionPreferenceController.java b/src/com/android/settings/applications/appinfo/AppPermissionPreferenceController.java
index bd309c6..b844f78 100644
--- a/src/com/android/settings/applications/appinfo/AppPermissionPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppPermissionPreferenceController.java
@@ -23,13 +23,10 @@
import android.icu.text.ListFormatter;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
import android.util.Log;
import com.android.settings.R;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settingslib.applications.PermissionsSummaryHelper;
-import com.android.settingslib.core.AbstractPreferenceController;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/com/android/settings/applications/appinfo/AppStoragePreferenceController.java b/src/com/android/settings/applications/appinfo/AppStoragePreferenceController.java
index d737288..86383cb 100644
--- a/src/com/android/settings/applications/appinfo/AppStoragePreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppStoragePreferenceController.java
@@ -28,7 +28,6 @@
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.applications.AppStorageSettings;
import com.android.settings.applications.FetchPackageStorageAsyncLoader;
import com.android.settingslib.applications.StorageStatsSource;
diff --git a/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java b/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java
index 82719f7..0cfeb008 100644
--- a/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java
@@ -21,7 +21,6 @@
import android.text.BidiFormatter;
import com.android.settings.R;
-import com.android.settings.applications.AppInfoDashboardFragment;
public class AppVersionPreferenceController extends AppInfoPreferenceControllerBase {
diff --git a/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBase.java b/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBase.java
index 3311daa..fa67ec8 100644
--- a/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBase.java
+++ b/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBase.java
@@ -51,11 +51,6 @@
}
@Override
- public Slice getSettingSlice() {
- return null;
- }
-
- @Override
public void updateState(Preference preference) {
preference.setSummary(isDefaultApp() ? R.string.yes : R.string.no);
}
diff --git a/src/com/android/settings/applications/appinfo/DrawOverlayDetailPreferenceController.java b/src/com/android/settings/applications/appinfo/DrawOverlayDetailPreferenceController.java
index 314d799..37a9edf 100644
--- a/src/com/android/settings/applications/appinfo/DrawOverlayDetailPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/DrawOverlayDetailPreferenceController.java
@@ -25,7 +25,6 @@
import android.support.v7.preference.Preference;
import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.applications.AppInfoDashboardFragment;
public class DrawOverlayDetailPreferenceController extends AppInfoPreferenceControllerBase {
diff --git a/src/com/android/settings/applications/appinfo/ExternalSourceDetailPreferenceController.java b/src/com/android/settings/applications/appinfo/ExternalSourceDetailPreferenceController.java
index 4ac67ed..6fb6dc3 100644
--- a/src/com/android/settings/applications/appinfo/ExternalSourceDetailPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/ExternalSourceDetailPreferenceController.java
@@ -22,7 +22,6 @@
import android.support.v7.preference.Preference;
import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.applications.AppStateInstallAppsBridge;
public class ExternalSourceDetailPreferenceController extends AppInfoPreferenceControllerBase {
diff --git a/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java b/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java
index 0400066..87e5fdb 100644
--- a/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java
+++ b/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java
@@ -107,6 +107,9 @@
@Override
protected boolean refreshUi() {
+ if (mPackageInfo == null || mPackageInfo.applicationInfo == null) {
+ return false;
+ }
if (mUserManager.hasBaseUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
UserHandle.of(UserHandle.myUserId()))) {
mSwitchPref.setChecked(false);
diff --git a/src/com/android/settings/applications/appinfo/InstantAppButtonsPreferenceController.java b/src/com/android/settings/applications/appinfo/InstantAppButtonsPreferenceController.java
new file mode 100644
index 0000000..b9fe003
--- /dev/null
+++ b/src/com/android/settings/applications/appinfo/InstantAppButtonsPreferenceController.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.applications.ApplicationFeatureProvider;
+import com.android.settings.applications.LayoutPreference;
+import com.android.settings.applications.instantapps.InstantAppButtonsController;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.applications.AppUtils;
+
+public class InstantAppButtonsPreferenceController extends BasePreferenceController {
+
+ private static final String KEY_INSTANT_APP_BUTTONS = "instant_app_buttons";
+
+ private final AppInfoDashboardFragment mParent;
+ private final String mPackageName;
+ private InstantAppButtonsController mInstantAppButtonsController;
+
+ public InstantAppButtonsPreferenceController(Context context, AppInfoDashboardFragment parent,
+ String packageName) {
+ super(context, KEY_INSTANT_APP_BUTTONS);
+ mParent = parent;
+ mPackageName = packageName;
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AppUtils.isInstant(mParent.getPackageInfo().applicationInfo)
+ ? AVAILABLE : DISABLED_FOR_USER;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ LayoutPreference buttons =
+ (LayoutPreference) screen.findPreference(KEY_INSTANT_APP_BUTTONS);
+ mInstantAppButtonsController = getApplicationFeatureProvider()
+ .newInstantAppButtonsController(mParent,
+ buttons.findViewById(R.id.instant_app_button_container),
+ id -> mParent.showDialogInner(id, 0))
+ .setPackageName(mPackageName)
+ .show();
+ }
+
+ public AlertDialog createDialog(int id) {
+ return mInstantAppButtonsController.createDialog(id);
+ }
+
+ @VisibleForTesting
+ ApplicationFeatureProvider getApplicationFeatureProvider() {
+ return FeatureFactory.getFactory(mContext).getApplicationFeatureProvider(mContext);
+ }
+}
diff --git a/src/com/android/settings/applications/appinfo/InstantAppDomainsPreferenceController.java b/src/com/android/settings/applications/appinfo/InstantAppDomainsPreferenceController.java
new file mode 100644
index 0000000..d89c538
--- /dev/null
+++ b/src/com/android/settings/applications/appinfo/InstantAppDomainsPreferenceController.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.Utils;
+import com.android.settings.applications.AppDomainsPreference;
+import com.android.settingslib.applications.AppUtils;
+
+import java.util.Set;
+
+public class InstantAppDomainsPreferenceController extends AppInfoPreferenceControllerBase {
+
+ private static final String KEY_INSTANT_APP_SUPPORTED_LINKS =
+ "instant_app_launch_supported_domain_urls";
+
+ private PackageManager mPackageManager;
+
+ public InstantAppDomainsPreferenceController(Context context, AppInfoDashboardFragment parent) {
+ super(context, parent, KEY_INSTANT_APP_SUPPORTED_LINKS);
+ mPackageManager = mContext.getPackageManager();
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AppUtils.isInstant(mParent.getPackageInfo().applicationInfo)
+ ? AVAILABLE : DISABLED_FOR_USER;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ final AppDomainsPreference instantAppDomainsPreference = (AppDomainsPreference) preference;
+ final Set<String> handledDomainSet =
+ Utils.getHandledDomains(mPackageManager, mParent.getPackageInfo().packageName);
+ final String[] handledDomains =
+ handledDomainSet.toArray(new String[handledDomainSet.size()]);
+ instantAppDomainsPreference.setTitles(handledDomains);
+ // Dummy values, unused in the implementation
+ instantAppDomainsPreference.setValues(new int[handledDomains.length]);
+ }
+
+}
diff --git a/src/com/android/settings/applications/appinfo/PictureInPictureDetailPreferenceController.java b/src/com/android/settings/applications/appinfo/PictureInPictureDetailPreferenceController.java
index aea6bae..1873683 100644
--- a/src/com/android/settings/applications/appinfo/PictureInPictureDetailPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/PictureInPictureDetailPreferenceController.java
@@ -26,7 +26,6 @@
import android.util.Log;
import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.applications.AppInfoDashboardFragment;
public class PictureInPictureDetailPreferenceController extends AppInfoPreferenceControllerBase {
diff --git a/src/com/android/settings/applications/appinfo/WriteSystemSettingsPreferenceController.java b/src/com/android/settings/applications/appinfo/WriteSystemSettingsPreferenceController.java
index 55b181a..2a88d2f 100644
--- a/src/com/android/settings/applications/appinfo/WriteSystemSettingsPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/WriteSystemSettingsPreferenceController.java
@@ -25,7 +25,6 @@
import android.support.v7.preference.Preference;
import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.applications.AppInfoDashboardFragment;
public class WriteSystemSettingsPreferenceController extends AppInfoPreferenceControllerBase {
diff --git a/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceController.java b/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceController.java
index a7d65d3..94aa608 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceController.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceController.java
@@ -100,7 +100,7 @@
Intent intent = new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
.setPackage(packageName)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
return mPackageManager.queryIntentActivities(intent, 0).size() == 1 ? intent : null;
}
diff --git a/src/com/android/settings/applications/instantapps/InstantAppButtonsController.java b/src/com/android/settings/applications/instantapps/InstantAppButtonsController.java
index 28e612c..42474a8 100644
--- a/src/com/android/settings/applications/instantapps/InstantAppButtonsController.java
+++ b/src/com/android/settings/applications/instantapps/InstantAppButtonsController.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.view.View;
import android.widget.Button;
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index 067e167..7371294 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -93,7 +93,7 @@
import com.android.settings.applications.InstalledAppDetails;
import com.android.settings.applications.NotificationApps;
import com.android.settings.applications.UsageAccessDetails;
-import com.android.settings.applications.AppInfoDashboardFragment;
+import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.applications.appinfo.DrawOverlayDetails;
import com.android.settings.applications.appinfo.ExternalSourcesDetails;
import com.android.settings.applications.appinfo.WriteSettingsDetails;
diff --git a/src/com/android/settings/backup/BackupSettingsActivityPreferenceController.java b/src/com/android/settings/backup/BackupSettingsActivityPreferenceController.java
index afc13b4..7a7530c 100644
--- a/src/com/android/settings/backup/BackupSettingsActivityPreferenceController.java
+++ b/src/com/android/settings/backup/BackupSettingsActivityPreferenceController.java
@@ -22,31 +22,29 @@
import android.support.v7.preference.Preference;
import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
-public class BackupSettingsActivityPreferenceController extends
- AbstractPreferenceController implements PreferenceControllerMixin {
+public class BackupSettingsActivityPreferenceController extends BasePreferenceController {
+ private static final String TAG = "BackupSettingActivityPC";
+
private static final String KEY_BACKUP_SETTINGS = "backup_settings";
- private static final String TAG = "BackupSettingActivityPC" ;
private final UserManager mUm;
private final BackupManager mBackupManager;
public BackupSettingsActivityPreferenceController(Context context) {
- super(context);
+ super(context, KEY_BACKUP_SETTINGS);
mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
mBackupManager = new BackupManager(context);
}
@Override
- public boolean isAvailable() {
- return mUm.isAdminUser();
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_BACKUP_SETTINGS;
+ public int getAvailabilityStatus() {
+ return mUm.isAdminUser()
+ ? AVAILABLE
+ : DISABLED_UNSUPPORTED;
}
@Override
@@ -57,4 +55,4 @@
? R.string.accessibility_feature_state_on
: R.string.accessibility_feature_state_off);
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceController.java b/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceController.java
index 8b07bcb..2d0ce60 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceController.java
@@ -29,10 +29,9 @@
import android.util.Log;
import com.android.settings.R;
-import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
@@ -41,8 +40,8 @@
/**
* Controller that shows and updates the bluetooth device name
*/
-public class BluetoothDeviceNamePreferenceController extends AbstractPreferenceController
- implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop {
+public class BluetoothDeviceNamePreferenceController extends BasePreferenceController implements
+ LifecycleObserver, OnStart, OnStop {
private static final String TAG = "BluetoothNamePrefCtrl";
public static final String KEY_DEVICE_NAME = "device_name";
@@ -62,12 +61,22 @@
return;
}
mLocalAdapter = mLocalManager.getBluetoothAdapter();
- lifecycle.addObserver(this);
+
+ if (lifecycle != null) {
+ lifecycle.addObserver(this);
+ }
+ }
+
+ /**
+ * Constructor exclusively used for Slice.
+ */
+ public BluetoothDeviceNamePreferenceController(Context context) {
+ this(context, (Lifecycle) null);
}
@VisibleForTesting
BluetoothDeviceNamePreferenceController(Context context, LocalBluetoothAdapter localAdapter) {
- super(context);
+ super(context, KEY_DEVICE_NAME);
mLocalAdapter = localAdapter;
}
@@ -89,8 +98,8 @@
}
@Override
- public boolean isAvailable() {
- return mLocalAdapter != null;
+ public int getAvailabilityStatus() {
+ return mLocalAdapter != null ? AVAILABLE : DISABLED_UNSUPPORTED;
}
@Override
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java b/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java
index b64da26..69eefcf 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
+import android.text.TextUtils;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
@@ -30,29 +31,39 @@
public class BluetoothDeviceRenamePreferenceController extends
BluetoothDeviceNamePreferenceController {
- public static final String PREF_KEY = "bt_rename_device";
-
private final Fragment mFragment;
+ private String mPrefKey;
private MetricsFeatureProvider mMetricsFeatureProvider;
- public BluetoothDeviceRenamePreferenceController(Context context, Fragment fragment,
- Lifecycle lifecycle) {
+ public BluetoothDeviceRenamePreferenceController(Context context, String prefKey,
+ Fragment fragment, Lifecycle lifecycle) {
super(context, lifecycle);
+ mPrefKey = prefKey;
mFragment = fragment;
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
}
+ /**
+ * Constructor exclusively used for Slice.
+ */
+ public BluetoothDeviceRenamePreferenceController(Context context, String prefKey) {
+ super(context, (Lifecycle) null);
+ mPrefKey = prefKey;
+ mFragment = null;
+ }
+
@VisibleForTesting
- BluetoothDeviceRenamePreferenceController(Context context, Fragment fragment,
+ BluetoothDeviceRenamePreferenceController(Context context, String prefKey, Fragment fragment,
LocalBluetoothAdapter localAdapter) {
super(context, localAdapter);
+ mPrefKey = prefKey;
mFragment = fragment;
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
}
@Override
public String getPreferenceKey() {
- return PREF_KEY;
+ return mPrefKey;
}
@Override
@@ -62,7 +73,7 @@
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
- if (PREF_KEY.equals(preference.getKey())) {
+ if (TextUtils.equals(mPrefKey, preference.getKey()) && mFragment != null) {
mMetricsFeatureProvider.action(mContext,
MetricsProto.MetricsEvent.ACTION_BLUETOOTH_RENAME);
LocalDeviceNameDialogFragment.newInstance()
diff --git a/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java b/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java
index d1492e4..331907b 100644
--- a/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java
+++ b/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java
@@ -38,6 +38,7 @@
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
+//TODO(b/69926683): remove this controller in Android P.
public class BluetoothMasterSwitchPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin, OnSummaryChangeListener, LifecycleObserver, OnResume,
OnPause, OnStart, OnStop {
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDetail.java b/src/com/android/settings/bluetooth/BluetoothPairingDetail.java
index a9756a6..5e003fe 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingDetail.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDetail.java
@@ -46,10 +46,9 @@
static final String KEY_AVAIL_DEVICES = "available_devices";
@VisibleForTesting
static final String KEY_FOOTER_PREF = "footer_preference";
+ private static final String KEY_RENAME_DEVICES = "bt_pair_rename_devices";
@VisibleForTesting
- BluetoothDeviceNamePreferenceController mDeviceNamePrefController;
- @VisibleForTesting
BluetoothProgressCategory mAvailableDevicesCategory;
@VisibleForTesting
FooterPreference mFooterPreference;
@@ -195,10 +194,10 @@
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
- List<AbstractPreferenceController> controllers = new ArrayList<>();
- mDeviceNamePrefController = new BluetoothDeviceNamePreferenceController(context,
- getLifecycle());
- controllers.add(mDeviceNamePrefController);
+ final List<AbstractPreferenceController> controllers = new ArrayList<>();
+ controllers.add(
+ new BluetoothDeviceRenamePreferenceController(context, KEY_RENAME_DEVICES, this,
+ getLifecycle()));
return controllers;
}
diff --git a/src/com/android/settings/bluetooth/BluetoothSettings.java b/src/com/android/settings/bluetooth/BluetoothSettings.java
index 72d8023..3acd477 100644
--- a/src/com/android/settings/bluetooth/BluetoothSettings.java
+++ b/src/com/android/settings/bluetooth/BluetoothSettings.java
@@ -73,6 +73,7 @@
static final String KEY_PAIRED_DEVICES = "paired_devices";
@VisibleForTesting
static final String KEY_FOOTER_PREF = "footer_preference";
+ private static final String KEY_RENAME_DEVICES = "bt_rename_device";
@VisibleForTesting
PreferenceGroup mPairedDevicesCategory;
@@ -369,7 +370,9 @@
controllers.add(mDeviceNamePrefController);
controllers.add(mPairingPrefController);
controllers.add(new BluetoothFilesPreferenceController(context));
- controllers.add(new BluetoothDeviceRenamePreferenceController(context, this, lifecycle));
+ controllers.add(
+ new BluetoothDeviceRenamePreferenceController(context, KEY_RENAME_DEVICES, this,
+ lifecycle));
return controllers;
}
diff --git a/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceController.java b/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceController.java
new file mode 100644
index 0000000..3482ee2
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceController.java
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+package com.android.settings.bluetooth;
+
+import android.content.Context;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.core.TogglePreferenceController;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.SwitchWidgetController;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+/**
+ * PreferenceController to update of bluetooth {@link SwitchPreference}. It will
+ *
+ * 1. Invoke the user toggle
+ * 2. Listen to the update from {@link LocalBluetoothManager}
+ */
+public class BluetoothSwitchPreferenceController extends TogglePreferenceController
+ implements LifecycleObserver, OnStart, OnStop {
+
+ public static final String KEY_TOGGLE_BLUETOOTH = "toggle_bluetooth_switch";
+
+ private LocalBluetoothManager mBluetoothManager;
+ private SwitchPreference mBtPreference;
+ private BluetoothEnabler mBluetoothEnabler;
+ private RestrictionUtils mRestrictionUtils;
+ @VisibleForTesting
+ LocalBluetoothAdapter mBluetoothAdapter;
+
+ public BluetoothSwitchPreferenceController(Context context) {
+ this(context, Utils.getLocalBtManager(context), new RestrictionUtils());
+ }
+
+ @VisibleForTesting
+ public BluetoothSwitchPreferenceController(Context context,
+ LocalBluetoothManager bluetoothManager, RestrictionUtils restrictionUtils) {
+ super(context, KEY_TOGGLE_BLUETOOTH);
+ mBluetoothManager = bluetoothManager;
+ mRestrictionUtils = restrictionUtils;
+
+ if (mBluetoothManager != null) {
+ mBluetoothAdapter = mBluetoothManager.getBluetoothAdapter();
+ }
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mBtPreference = (SwitchPreference) screen.findPreference(KEY_TOGGLE_BLUETOOTH);
+ mBluetoothEnabler = new BluetoothEnabler(mContext,
+ new SwitchController(mBtPreference),
+ FeatureFactory.getFactory(mContext).getMetricsFeatureProvider(), mBluetoothManager,
+ MetricsEvent.ACTION_SETTINGS_MASTER_SWITCH_BLUETOOTH_TOGGLE,
+ mRestrictionUtils);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return mBluetoothAdapter != null ? AVAILABLE : DISABLED_UNSUPPORTED;
+ }
+
+ @Override
+ public void onStart() {
+ mBluetoothEnabler.resume(mContext);
+ }
+
+ @Override
+ public void onStop() {
+ mBluetoothEnabler.pause();
+ }
+
+ @Override
+ public boolean isChecked() {
+ return mBluetoothAdapter != null ? mBluetoothAdapter.isEnabled() : false;
+ }
+
+ @Override
+ public void setChecked(boolean isChecked) {
+ if (mBluetoothAdapter != null) {
+ mBluetoothAdapter.setBluetoothEnabled(isChecked);
+ }
+ }
+
+ /**
+ * Control the switch inside {@link SwitchPreference}
+ */
+ @VisibleForTesting
+ class SwitchController extends SwitchWidgetController implements
+ Preference.OnPreferenceChangeListener {
+ private SwitchPreference mSwitchPreference;
+
+ public SwitchController(SwitchPreference switchPreference) {
+ mSwitchPreference = switchPreference;
+ }
+
+ @Override
+ public void updateTitle(boolean isChecked) {
+ }
+
+ @Override
+ public void startListening() {
+ mSwitchPreference.setOnPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void stopListening() {
+ mSwitchPreference.setOnPreferenceChangeListener(null);
+ }
+
+ @Override
+ public void setChecked(boolean checked) {
+ mSwitchPreference.setChecked(checked);
+ }
+
+ @Override
+ public boolean isChecked() {
+ return mSwitchPreference.isChecked();
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ mSwitchPreference.setEnabled(enabled);
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (mListener != null) {
+ return mListener.onSwitchToggled((Boolean) newValue);
+ }
+ return false;
+ }
+
+ @Override
+ public void setDisabledByAdmin(RestrictedLockUtils.EnforcedAdmin admin) {
+ mBtPreference.setEnabled(admin == null);
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/DeviceProfilesSettings.java b/src/com/android/settings/bluetooth/DeviceProfilesSettings.java
old mode 100755
new mode 100644
index eae2f29..d13a85f
--- a/src/com/android/settings/bluetooth/DeviceProfilesSettings.java
+++ b/src/com/android/settings/bluetooth/DeviceProfilesSettings.java
@@ -172,7 +172,11 @@
mProfileContainer.removeAllViews();
for (LocalBluetoothProfile profile : mCachedDevice.getConnectableProfiles()) {
CheckBox pref = createProfilePreference(profile);
- mProfileContainer.addView(pref);
+ // MAP and PBAP profiles would be added based on permission access
+ if (!((profile instanceof PbapServerProfile) ||
+ (profile instanceof MapProfile))) {
+ mProfileContainer.addView(pref);
+ }
if (profile instanceof A2dpProfile) {
BluetoothDevice device = mCachedDevice.getDevice();
@@ -191,6 +195,7 @@
}
final int pbapPermission = mCachedDevice.getPhonebookPermissionChoice();
+ Log.d(TAG, "addPreferencesForProfiles: pbapPermission = " + pbapPermission);
// Only provide PBAP cabability if the client device has requested PBAP.
if (pbapPermission != CachedBluetoothDevice.ACCESS_UNKNOWN) {
final PbapServerProfile psp = mManager.getProfileManager().getPbapProfile();
@@ -200,6 +205,7 @@
final MapProfile mapProfile = mManager.getProfileManager().getMapProfile();
final int mapPermission = mCachedDevice.getMessagePermissionChoice();
+ Log.d(TAG, "addPreferencesForProfiles: mapPermission = " + mapPermission);
if (mapPermission != CachedBluetoothDevice.ACCESS_UNKNOWN) {
CheckBox mapPreference = createProfilePreference(mapProfile);
mProfileContainer.addView(mapPreference);
@@ -251,15 +257,6 @@
private void onProfileClicked(LocalBluetoothProfile profile, CheckBox profilePref) {
BluetoothDevice device = mCachedDevice.getDevice();
- if (KEY_PBAP_SERVER.equals(profilePref.getTag())) {
- final int newPermission = mCachedDevice.getPhonebookPermissionChoice()
- == CachedBluetoothDevice.ACCESS_ALLOWED ? CachedBluetoothDevice.ACCESS_REJECTED
- : CachedBluetoothDevice.ACCESS_ALLOWED;
- mCachedDevice.setPhonebookPermissionChoice(newPermission);
- profilePref.setChecked(newPermission == CachedBluetoothDevice.ACCESS_ALLOWED);
- return;
- }
-
if (!profilePref.isChecked()) {
// Recheck it, until the dialog is done.
profilePref.setChecked(true);
@@ -268,6 +265,12 @@
if (profile instanceof MapProfile) {
mCachedDevice.setMessagePermissionChoice(BluetoothDevice.ACCESS_ALLOWED);
}
+ if (profile instanceof PbapServerProfile) {
+ mCachedDevice.setPhonebookPermissionChoice(BluetoothDevice.ACCESS_ALLOWED);
+ refreshProfilePreference(profilePref, profile);
+ // PBAP server is not preffered profile and cannot initiate connection, so return
+ return;
+ }
if (profile.isPreferred(device)) {
// profile is preferred but not connected: disable auto-connect
if (profile instanceof PanProfile) {
@@ -301,10 +304,17 @@
DialogInterface.OnClickListener disconnectListener =
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
- device.disconnect(profile);
- profile.setPreferred(device.getDevice(), false);
- if (profile instanceof MapProfile) {
- device.setMessagePermissionChoice(BluetoothDevice.ACCESS_REJECTED);
+
+ // Disconnect only when user has selected OK otherwise ignore
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ device.disconnect(profile);
+ profile.setPreferred(device.getDevice(), false);
+ if (profile instanceof MapProfile) {
+ device.setMessagePermissionChoice(BluetoothDevice.ACCESS_REJECTED);
+ }
+ if (profile instanceof PbapServerProfile) {
+ device.setPhonebookPermissionChoice(BluetoothDevice.ACCESS_REJECTED);
+ }
}
refreshProfilePreference(findProfile(profile.toString()), profile);
}
@@ -342,6 +352,19 @@
for (LocalBluetoothProfile profile : mCachedDevice.getRemovedProfiles()) {
CheckBox profilePref = findProfile(profile.toString());
if (profilePref != null) {
+
+ if (profile instanceof PbapServerProfile) {
+ final int pbapPermission = mCachedDevice.getPhonebookPermissionChoice();
+ Log.d(TAG, "refreshProfiles: pbapPermission = " + pbapPermission);
+ if (pbapPermission != CachedBluetoothDevice.ACCESS_UNKNOWN)
+ continue;
+ }
+ if (profile instanceof MapProfile) {
+ final int mapPermission = mCachedDevice.getMessagePermissionChoice();
+ Log.d(TAG, "refreshProfiles: mapPermission = " + mapPermission);
+ if (mapPermission != CachedBluetoothDevice.ACCESS_UNKNOWN)
+ continue;
+ }
Log.d(TAG, "Removing " + profile.toString() + " from profile list");
mProfileContainer.removeView(profilePref);
}
diff --git a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
index ea93fef..a4f6e5c 100644
--- a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java
@@ -24,6 +24,7 @@
import com.android.settings.SettingsActivity;
import com.android.settings.bluetooth.BluetoothFilesPreferenceController;
import com.android.settings.bluetooth.BluetoothMasterSwitchPreferenceController;
+import com.android.settings.bluetooth.BluetoothSwitchPreferenceController;
import com.android.settings.bluetooth.Utils;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.deviceinfo.UsbBackend;
@@ -83,10 +84,8 @@
mUsbPrefController = new UsbModePreferenceController(context, new UsbBackend(context));
lifecycle.addObserver(mUsbPrefController);
controllers.add(mUsbPrefController);
- final BluetoothMasterSwitchPreferenceController bluetoothPreferenceController =
- new BluetoothMasterSwitchPreferenceController(
- context, Utils.getLocalBtManager(context), this,
- (SettingsActivity) getActivity());
+ final BluetoothSwitchPreferenceController bluetoothPreferenceController =
+ new BluetoothSwitchPreferenceController(context);
lifecycle.addObserver(bluetoothPreferenceController);
controllers.add(bluetoothPreferenceController);
diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java b/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java
index a0b5cb8..3cccc15 100644
--- a/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java
+++ b/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java
@@ -19,6 +19,7 @@
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
+
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.bluetooth.BluetoothDeviceUpdater;
import com.android.settings.bluetooth.ConnectedBluetoothDeviceUpdater;
@@ -42,26 +43,31 @@
@VisibleForTesting
PreferenceGroup mPreferenceGroup;
private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
+ private ConnectedUsbDeviceUpdater mConnectedUsbDeviceUpdater;
public ConnectedDeviceGroupController(DashboardFragment fragment, Lifecycle lifecycle) {
super(fragment.getContext());
- init(lifecycle, new ConnectedBluetoothDeviceUpdater(fragment, this));
+ init(lifecycle, new ConnectedBluetoothDeviceUpdater(fragment, this),
+ new ConnectedUsbDeviceUpdater(fragment.getContext(), this));
}
@VisibleForTesting
ConnectedDeviceGroupController(DashboardFragment fragment, Lifecycle lifecycle,
- BluetoothDeviceUpdater bluetoothDeviceUpdater) {
+ BluetoothDeviceUpdater bluetoothDeviceUpdater,
+ ConnectedUsbDeviceUpdater connectedUsbDeviceUpdater) {
super(fragment.getContext());
- init(lifecycle, bluetoothDeviceUpdater);
+ init(lifecycle, bluetoothDeviceUpdater, connectedUsbDeviceUpdater);
}
@Override
public void onStart() {
mBluetoothDeviceUpdater.registerCallback();
+ mConnectedUsbDeviceUpdater.registerCallback();
}
@Override
public void onStop() {
+ mConnectedUsbDeviceUpdater.unregisterCallback();
mBluetoothDeviceUpdater.unregisterCallback();
}
@@ -70,8 +76,10 @@
super.displayPreference(screen);
mPreferenceGroup = (PreferenceGroup) screen.findPreference(KEY);
mPreferenceGroup.setVisible(false);
+
mBluetoothDeviceUpdater.setPrefContext(screen.getContext());
mBluetoothDeviceUpdater.forceUpdate();
+ mConnectedUsbDeviceUpdater.initUsbPreference(screen.getContext());
}
@Override
@@ -100,10 +108,12 @@
}
}
- private void init(Lifecycle lifecycle, BluetoothDeviceUpdater bluetoothDeviceUpdater) {
+ private void init(Lifecycle lifecycle, BluetoothDeviceUpdater bluetoothDeviceUpdater,
+ ConnectedUsbDeviceUpdater connectedUsbDeviceUpdater) {
if (lifecycle != null) {
lifecycle.addObserver(this);
}
mBluetoothDeviceUpdater = bluetoothDeviceUpdater;
+ mConnectedUsbDeviceUpdater = connectedUsbDeviceUpdater;
}
}
diff --git a/src/com/android/settings/connecteddevice/ConnectedUsbDeviceUpdater.java b/src/com/android/settings/connecteddevice/ConnectedUsbDeviceUpdater.java
new file mode 100644
index 0000000..0468b0f
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/ConnectedUsbDeviceUpdater.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+package com.android.settings.connecteddevice;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.annotation.VisibleForTesting;
+
+import com.android.settings.R;
+import com.android.settings.deviceinfo.UsbBackend;
+import com.android.settings.deviceinfo.UsbModeChooserActivity;
+import com.android.settings.widget.GearPreference;
+
+/**
+ * Controller to maintain connected usb device
+ */
+public class ConnectedUsbDeviceUpdater {
+ private Context mContext;
+ private UsbBackend mUsbBackend;
+ private DevicePreferenceCallback mDevicePreferenceCallback;
+ @VisibleForTesting
+ GearPreference mUsbPreference;
+ @VisibleForTesting
+ UsbConnectionBroadcastReceiver mUsbReceiver;
+
+ private UsbConnectionBroadcastReceiver.UsbConnectionListener mUsbConnectionListener =
+ (connected) -> {
+ if (connected) {
+ mUsbPreference.setSummary(
+ UsbModePreferenceController.getSummary(mUsbBackend.getCurrentMode()));
+ mDevicePreferenceCallback.onDeviceAdded(mUsbPreference);
+ } else {
+ mDevicePreferenceCallback.onDeviceRemoved(mUsbPreference);
+ }
+ };
+
+ public ConnectedUsbDeviceUpdater(Context context,
+ DevicePreferenceCallback devicePreferenceCallback) {
+ this(context, devicePreferenceCallback, new UsbBackend(context));
+ }
+
+ @VisibleForTesting
+ ConnectedUsbDeviceUpdater(Context context, DevicePreferenceCallback devicePreferenceCallback,
+ UsbBackend usbBackend) {
+ mContext = context;
+ mDevicePreferenceCallback = devicePreferenceCallback;
+ mUsbBackend = usbBackend;
+ mUsbReceiver = new UsbConnectionBroadcastReceiver(context, mUsbConnectionListener);
+ }
+
+ public void registerCallback() {
+ // This method could handle multiple register
+ mUsbReceiver.register();
+ }
+
+ public void unregisterCallback() {
+ mUsbReceiver.unregister();
+ }
+
+ public void initUsbPreference(Context context) {
+ mUsbPreference = new GearPreference(context, null /* AttributeSet */);
+ mUsbPreference.setTitle(R.string.usb_pref);
+ mUsbPreference.setIcon(R.drawable.ic_usb);
+ mUsbPreference.setSelectable(false);
+ mUsbPreference.setOnGearClickListener((GearPreference p) -> {
+ final Intent intent = new Intent(mContext, UsbModeChooserActivity.class);
+ mContext.startActivity(intent);
+ });
+
+ forceUpdate();
+ }
+
+ private void forceUpdate() {
+ // Register so we can get the connection state from sticky intent.
+ //TODO(b/70336520): Use an API to get data instead of sticky intent
+ mUsbReceiver.register();
+ mUsbConnectionListener.onUsbConnectionChanged(mUsbReceiver.isConnected());
+ }
+}
diff --git a/src/com/android/settings/connecteddevice/UsbConnectionBroadcastReceiver.java b/src/com/android/settings/connecteddevice/UsbConnectionBroadcastReceiver.java
new file mode 100644
index 0000000..07a7691
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/UsbConnectionBroadcastReceiver.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+package com.android.settings.connecteddevice;
+
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbManager;
+
+/**
+ * Receiver to receive usb update and use {@link UsbConnectionListener} to invoke callback
+ */
+public class UsbConnectionBroadcastReceiver extends BroadcastReceiver {
+ private Context mContext;
+ private UsbConnectionListener mUsbConnectionListener;
+ private boolean mListeningToUsbEvents;
+ private boolean mConnected;
+
+ public UsbConnectionBroadcastReceiver(Context context,
+ UsbConnectionListener usbConnectionListener) {
+ mContext = context;
+ mUsbConnectionListener = usbConnectionListener;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mConnected = intent != null
+ && intent.getExtras().getBoolean(UsbManager.USB_CONNECTED);
+ if (mUsbConnectionListener != null) {
+ mUsbConnectionListener.onUsbConnectionChanged(mConnected);
+ }
+ }
+
+ public void register() {
+ if (!mListeningToUsbEvents) {
+ final IntentFilter intentFilter = new IntentFilter(UsbManager.ACTION_USB_STATE);
+ final Intent intent = mContext.registerReceiver(this, intentFilter);
+ mConnected = intent != null
+ && intent.getExtras().getBoolean(UsbManager.USB_CONNECTED);
+ mListeningToUsbEvents = true;
+ }
+ }
+
+ public void unregister() {
+ if (mListeningToUsbEvents) {
+ mContext.unregisterReceiver(this);
+ mListeningToUsbEvents = false;
+ }
+ }
+
+ public boolean isConnected() {
+ return mConnected;
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when usb connection is changed.
+ */
+ interface UsbConnectionListener {
+ void onUsbConnectionChanged(boolean connected);
+ }
+}
diff --git a/src/com/android/settings/connecteddevice/UsbModePreferenceController.java b/src/com/android/settings/connecteddevice/UsbModePreferenceController.java
index a6cb9be..8693520 100644
--- a/src/com/android/settings/connecteddevice/UsbModePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/UsbModePreferenceController.java
@@ -15,17 +15,12 @@
*/
package com.android.settings.connecteddevice;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.hardware.usb.UsbManager;
-import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
-import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.deviceinfo.UsbBackend;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -44,19 +39,21 @@
public UsbModePreferenceController(Context context, UsbBackend usbBackend) {
super(context);
mUsbBackend = usbBackend;
- mUsbReceiver = new UsbConnectionBroadcastReceiver();
+ mUsbReceiver = new UsbConnectionBroadcastReceiver(mContext, (connected) -> {
+ updateSummary(mUsbPreference);
+ });
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mUsbPreference = screen.findPreference(KEY_USB_MODE);
- updataSummary(mUsbPreference);
+ updateSummary(mUsbPreference);
}
@Override
public void updateState(Preference preference) {
- updataSummary(preference);
+ updateSummary(preference);
}
@Override
@@ -79,8 +76,7 @@
mUsbReceiver.register();
}
- @VisibleForTesting
- int getSummary(int mode) {
+ public static int getSummary(int mode) {
switch (mode) {
case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_NONE:
return R.string.usb_summary_charging_only;
@@ -96,11 +92,11 @@
return 0;
}
- private void updataSummary(Preference preference) {
- updataSummary(preference, mUsbBackend.getCurrentMode());
+ private void updateSummary(Preference preference) {
+ updateSummary(preference, mUsbBackend.getCurrentMode());
}
- private void updataSummary(Preference preference, int mode) {
+ private void updateSummary(Preference preference, int mode) {
if (preference != null) {
if (mUsbReceiver.isConnected()) {
preference.setEnabled(true);
@@ -112,40 +108,4 @@
}
}
- private class UsbConnectionBroadcastReceiver extends BroadcastReceiver {
- private boolean mListeningToUsbEvents;
- private boolean mConnected;
-
- @Override
- public void onReceive(Context context, Intent intent) {
- boolean connected = intent != null
- && intent.getExtras().getBoolean(UsbManager.USB_CONNECTED);
- if (connected != mConnected) {
- mConnected = connected;
- updataSummary(mUsbPreference);
- }
- }
-
- public void register() {
- if (!mListeningToUsbEvents) {
- IntentFilter intentFilter = new IntentFilter(UsbManager.ACTION_USB_STATE);
- Intent intent = mContext.registerReceiver(this, intentFilter);
- mConnected = intent != null
- && intent.getExtras().getBoolean(UsbManager.USB_CONNECTED);
- mListeningToUsbEvents = true;
- }
- }
-
- public void unregister() {
- if (mListeningToUsbEvents) {
- mContext.unregisterReceiver(this);
- mListeningToUsbEvents = false;
- }
- }
-
- public boolean isConnected() {
- return mConnected;
- }
- }
-
}
diff --git a/src/com/android/settings/core/BasePreferenceController.java b/src/com/android/settings/core/BasePreferenceController.java
index b3d9878..01d98b8 100644
--- a/src/com/android/settings/core/BasePreferenceController.java
+++ b/src/com/android/settings/core/BasePreferenceController.java
@@ -14,14 +14,10 @@
package com.android.settings.core;
import android.annotation.IntDef;
-import android.app.slice.Slice;
import android.content.Context;
-import android.support.v7.preference.Preference;
import android.text.TextUtils;
import android.util.Log;
-
-import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.search.ResultPayload;
import com.android.settings.search.SearchIndexableRaw;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -88,11 +84,6 @@
@AvailabilityStatus
public abstract int getAvailabilityStatus();
- /**
- * @return A slice for the corresponding setting.
- */
- public abstract Slice getSettingSlice();
-
@Override
public String getPreferenceKey() {
return mPreferenceKey;
@@ -150,10 +141,4 @@
public ResultPayload getResultPayload() {
return null;
}
-
- // TODO (b/69380366) Add Method to get preference UI
-
- // TODO (b/69380464) Add method to get intent
-
- // TODO (b/69380560) Add method to get broadcast intent
}
\ No newline at end of file
diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java
index 9ceef47..4371b4a 100644
--- a/src/com/android/settings/core/FeatureFlags.java
+++ b/src/com/android/settings/core/FeatureFlags.java
@@ -20,7 +20,6 @@
* This class keeps track of all feature flags in Settings.
*/
public class FeatureFlags {
- public static final String DEVICE_INFO_V2 = "device_info_v2";
public static final String SEARCH_V2 = "settings_search_v2";
public static final String SUGGESTIONS_V2 = "new_settings_suggestion";
public static final String APP_INFO_V2 = "settings_app_info_v2";
diff --git a/src/com/android/settings/core/TogglePreferenceController.java b/src/com/android/settings/core/TogglePreferenceController.java
index 03106d3..99d2ecc 100644
--- a/src/com/android/settings/core/TogglePreferenceController.java
+++ b/src/com/android/settings/core/TogglePreferenceController.java
@@ -13,7 +13,6 @@
*/
package com.android.settings.core;
-import android.app.slice.Slice;
import android.content.Context;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
@@ -55,10 +54,4 @@
setChecked(auto);
return true;
}
-
- @Override
- public Slice getSettingSlice() {
- // TODO
- return null;
- }
}
\ No newline at end of file
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index ecef57e..b7c73f3 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -47,7 +47,7 @@
import com.android.settings.applications.ProcessStatsUi;
import com.android.settings.applications.UsageAccessDetails;
import com.android.settings.applications.VrListenerSettings;
-import com.android.settings.applications.AppInfoDashboardFragment;
+import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.applications.appinfo.DrawOverlayDetails;
import com.android.settings.applications.appinfo.ExternalSourcesDetails;
import com.android.settings.applications.appinfo.PictureInPictureDetails;
@@ -65,12 +65,9 @@
import com.android.settings.datausage.DataUsageSummary;
import com.android.settings.deletionhelper.AutomaticStorageManagerSettings;
import com.android.settings.development.DevelopmentSettingsDashboardFragment;
-import com.android.settings.deviceinfo.ImeiInformation;
import com.android.settings.deviceinfo.PrivateVolumeForget;
import com.android.settings.deviceinfo.PrivateVolumeSettings;
import com.android.settings.deviceinfo.PublicVolumeSettings;
-import com.android.settings.deviceinfo.SimStatus;
-import com.android.settings.deviceinfo.Status;
import com.android.settings.deviceinfo.StorageDashboardFragment;
import com.android.settings.deviceinfo.StorageSettings;
import com.android.settings.display.NightDisplaySettings;
@@ -235,9 +232,6 @@
ManagedProfileSettings.class.getName(),
ChooseAccountActivity.class.getName(),
IccLockSettings.class.getName(),
- ImeiInformation.class.getName(),
- SimStatus.class.getName(),
- Status.class.getName(),
TestingSettings.class.getName(),
WifiAPITest.class.getName(),
WifiInfo.class.getName(),
@@ -271,6 +265,7 @@
Settings.SoundSettingsActivity.class.getName(),
Settings.StorageDashboardActivity.class.getName(),
Settings.PowerUsageSummaryActivity.class.getName(),
+ Settings.PowerUsageSummaryLegacyActivity.class.getName(),
Settings.UserAndAccountDashboardActivity.class.getName(),
Settings.SecuritySettingsActivity.class.getName(),
Settings.AccessibilitySettingsActivity.class.getName(),
diff --git a/src/com/android/settings/datausage/UnrestrictedDataAccess.java b/src/com/android/settings/datausage/UnrestrictedDataAccess.java
index 5b55ada..e8a7bbf 100644
--- a/src/com/android/settings/datausage/UnrestrictedDataAccess.java
+++ b/src/com/android/settings/datausage/UnrestrictedDataAccess.java
@@ -32,7 +32,7 @@
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.applications.AppStateBaseBridge;
import com.android.settings.applications.InstalledAppDetails;
-import com.android.settings.applications.AppInfoDashboardFragment;
+import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.core.FeatureFlags;
import com.android.settings.datausage.AppStateDataUsageBridge.DataUsageState;
import com.android.settings.overlay.FeatureFactory;
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 8f114fc..e736798 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -446,6 +446,7 @@
controllers.add(new ResizableActivityPreferenceController(context));
controllers.add(new FreeformWindowsPreferenceController(context));
controllers.add(new ShortcutManagerThrottlingPreferenceController(context));
+ controllers.add(new EnableGnssRawMeasFullTrackingPreferenceController(context));
return controllers;
}
diff --git a/src/com/android/settings/development/EnableGnssRawMeasFullTrackingPreferenceController.java b/src/com/android/settings/development/EnableGnssRawMeasFullTrackingPreferenceController.java
new file mode 100644
index 0000000..09770f6
--- /dev/null
+++ b/src/com/android/settings/development/EnableGnssRawMeasFullTrackingPreferenceController.java
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.development;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+public class EnableGnssRawMeasFullTrackingPreferenceController extends
+ DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener,
+ PreferenceControllerMixin {
+
+ private static final String ENABLE_GNSS_RAW_MEAS_FULL_TRACKING_KEY =
+ "enable_gnss_raw_meas_full_tracking";
+
+ static final int SETTING_VALUE_ON = 1;
+ static final int SETTING_VALUE_OFF = 0;
+
+ private SwitchPreference mPreference;
+
+ public EnableGnssRawMeasFullTrackingPreferenceController(Context context) {
+ super(context);
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return ENABLE_GNSS_RAW_MEAS_FULL_TRACKING_KEY;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+
+ mPreference = (SwitchPreference) screen.findPreference(getPreferenceKey());
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ final boolean isEnabled = (Boolean) newValue;
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
+ isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
+
+ return true;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ final int enableGnssRawMeasFullTrackingMode =
+ Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, SETTING_VALUE_OFF);
+ mPreference.setChecked(enableGnssRawMeasFullTrackingMode != SETTING_VALUE_OFF);
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchEnabled() {
+ mPreference.setEnabled(true);
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchDisabled() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, SETTING_VALUE_OFF);
+ mPreference.setEnabled(false);
+ mPreference.setChecked(false);
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java b/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java
index 06bdb3f..f91ed4e 100644
--- a/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceController.java
@@ -17,26 +17,23 @@
import android.content.Context;
+import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
-public class AdditionalSystemUpdatePreferenceController extends
- AbstractPreferenceController implements PreferenceControllerMixin {
+public class AdditionalSystemUpdatePreferenceController extends BasePreferenceController {
private static final String KEY_UPDATE_SETTING = "additional_system_update_settings";
public AdditionalSystemUpdatePreferenceController(Context context) {
- super(context);
+ super(context, KEY_UPDATE_SETTING);
}
@Override
- public boolean isAvailable() {
+ public int getAvailabilityStatus() {
return mContext.getResources().getBoolean(
- com.android.settings.R.bool.config_additional_system_update_setting_enable);
+ com.android.settings.R.bool.config_additional_system_update_setting_enable)
+ ? AVAILABLE
+ : DISABLED_UNSUPPORTED;
}
-
- @Override
- public String getPreferenceKey() {
- return KEY_UPDATE_SETTING;
- }
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/deviceinfo/BasebandVersionPreferenceController.java b/src/com/android/settings/deviceinfo/BasebandVersionPreferenceController.java
deleted file mode 100644
index 06ed872..0000000
--- a/src/com/android/settings/deviceinfo/BasebandVersionPreferenceController.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.
- */
-package com.android.settings.deviceinfo;
-
-import android.content.Context;
-import android.os.SystemProperties;
-import android.support.v7.preference.Preference;
-
-import com.android.settings.R;
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.deviceinfo.firmwareversion.BasebandVersionDialogController;
-import com.android.settingslib.Utils;
-import com.android.settingslib.core.AbstractPreferenceController;
-
-/**
- * deprecated in favor of {@link BasebandVersionDialogController}
- */
-@Deprecated
-public class BasebandVersionPreferenceController extends AbstractPreferenceController implements
- PreferenceControllerMixin {
-
- private static final String BASEBAND_PROPERTY = "gsm.version.baseband";
- private static final String KEY_BASEBAND_VERSION = "baseband_version";
-
- public BasebandVersionPreferenceController(Context context) {
- super(context);
- }
-
- @Override
- public boolean isAvailable() {
- return !Utils.isWifiOnly(mContext);
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_BASEBAND_VERSION;
- }
-
- @Override
- public void updateState(Preference preference) {
- super.updateState(preference);
- preference.setSummary(SystemProperties.get(BASEBAND_PROPERTY,
- mContext.getResources().getString(R.string.device_info_default)));
- }
-}
diff --git a/src/com/android/settings/deviceinfo/BatteryInfoPreferenceController.java b/src/com/android/settings/deviceinfo/BatteryInfoPreferenceController.java
deleted file mode 100644
index b5c12f7..0000000
--- a/src/com/android/settings/deviceinfo/BatteryInfoPreferenceController.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.settings.deviceinfo;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.support.annotation.VisibleForTesting;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
-
-import com.android.settings.Utils;
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.fuelgauge.PowerUsageSummary;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnStart;
-import com.android.settingslib.core.lifecycle.events.OnStop;
-
-/**
- * Deprecated in About Phone V2
- * Information in this preference is available in {@link PowerUsageSummary}
- */
-@Deprecated
-public class BatteryInfoPreferenceController extends AbstractPreferenceController
- implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop {
-
- @VisibleForTesting
- static final IntentFilter BATTERY_INFO_RECEIVER_INTENT_FILTER =
- new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
- @VisibleForTesting
- static final String KEY_BATTERY_STATUS = "battery_status";
- @VisibleForTesting
- static final String KEY_BATTERY_LEVEL = "battery_level";
-
- @VisibleForTesting
- BroadcastReceiver mBatteryInfoReceiver;
- private Preference mBatteryStatus;
- private Preference mBatteryLevel;
-
-
- public BatteryInfoPreferenceController(Context context, Lifecycle lifecycle) {
- super(context);
- mBatteryInfoReceiver = new BatteryInfoReceiver(context);
- if (lifecycle != null) {
- lifecycle.addObserver(this);
- }
- }
-
- @Override
- public boolean isAvailable() {
- return true;
- }
-
- @Override
- public String getPreferenceKey() {
- return null;
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- mBatteryLevel = screen.findPreference(KEY_BATTERY_LEVEL);
- mBatteryStatus = screen.findPreference(KEY_BATTERY_STATUS);
- }
-
- @Override
- public void onStart() {
- mContext.registerReceiver(mBatteryInfoReceiver, BATTERY_INFO_RECEIVER_INTENT_FILTER);
- }
-
- @Override
- public void onStop() {
- mContext.unregisterReceiver(mBatteryInfoReceiver);
- }
-
- private class BatteryInfoReceiver extends BroadcastReceiver {
-
- private final Context mContext;
-
- public BatteryInfoReceiver(Context context) {
- mContext = context;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
- mBatteryLevel.setSummary(Utils.getBatteryPercentage(intent));
- mBatteryStatus.setSummary(Utils.getBatteryStatus(mContext.getResources(), intent));
- }
- }
- }
-}
diff --git a/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java b/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java
index 7934ad7..ee069da 100644
--- a/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java
@@ -21,10 +21,8 @@
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;
-import android.util.FeatureFlagUtils;
import com.android.settings.R;
-import com.android.settings.core.FeatureFlags;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.DeviceInfoUtils;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -51,12 +49,8 @@
super.displayPreference(screen);
final Preference pref = screen.findPreference(KEY_DEVICE_MODEL);
if (pref != null) {
- if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.DEVICE_INFO_V2)) {
- pref.setSummary(mContext.getResources().getString(R.string.model_summary,
- getDeviceModel()));
- } else {
- pref.setSummary(getDeviceModel());
- }
+ pref.setSummary(mContext.getResources().getString(R.string.model_summary,
+ getDeviceModel()));
}
}
diff --git a/src/com/android/settings/deviceinfo/FirmwareVersionPreferenceController.java b/src/com/android/settings/deviceinfo/FirmwareVersionPreferenceController.java
deleted file mode 100644
index 8c9a2f1..0000000
--- a/src/com/android/settings/deviceinfo/FirmwareVersionPreferenceController.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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.
- */
-package com.android.settings.deviceinfo;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Build;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.deviceinfo.firmwareversion.FirmwareVersionPreferenceControllerV2;
-import com.android.settingslib.RestrictedLockUtils;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnResume;
-
-/**
- * deprecated in favor of {@link FirmwareVersionPreferenceControllerV2}
- */
-@Deprecated
-public class FirmwareVersionPreferenceController extends AbstractPreferenceController implements
- PreferenceControllerMixin, LifecycleObserver, OnResume {
-
- private static final String TAG = "FirmwareVersionPref";
- private static final String KEY_FIRMWARE_VERSION = "firmware_version";
-
- private final UserManager mUserManager;
-
- private RestrictedLockUtils.EnforcedAdmin mFunDisallowedAdmin;
- private boolean mFunDisallowedBySystem;
-
- private long[] mHits = new long[3];
-
- public FirmwareVersionPreferenceController(Context context, Lifecycle lifecycle) {
- super(context);
- mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- if (lifecycle != null) {
- lifecycle.addObserver(this);
- }
- }
-
- @Override
- public boolean isAvailable() {
- return true;
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- final Preference pref = screen.findPreference(KEY_FIRMWARE_VERSION);
- if (pref != null) {
- pref.setSummary(Build.VERSION.RELEASE);
- }
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_FIRMWARE_VERSION;
- }
-
- @Override
- public void onResume() {
- mFunDisallowedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(
- mContext, UserManager.DISALLOW_FUN, UserHandle.myUserId());
- mFunDisallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction(
- mContext, UserManager.DISALLOW_FUN, UserHandle.myUserId());
- }
-
- @Override
- public boolean handlePreferenceTreeClick(Preference preference) {
- if (!TextUtils.equals(preference.getKey(), KEY_FIRMWARE_VERSION)) {
- return false;
- }
- System.arraycopy(mHits, 1, mHits, 0, mHits.length - 1);
- mHits[mHits.length - 1] = SystemClock.uptimeMillis();
- if (mHits[0] >= (SystemClock.uptimeMillis() - 500)) {
- if (mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN)) {
- if (mFunDisallowedAdmin != null && !mFunDisallowedBySystem) {
- RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext,
- mFunDisallowedAdmin);
- }
- Log.d(TAG, "Sorry, no fun for you!");
- return false;
- }
-
- final Intent intent = new Intent(Intent.ACTION_MAIN)
- .setClassName(
- "android", com.android.internal.app.PlatLogoActivity.class.getName());
- try {
- mContext.startActivity(intent);
- return true;
- } catch (Exception e) {
- Log.e(TAG, "Unable to start activity " + intent.toString());
- }
- }
- return false;
- }
-}
diff --git a/src/com/android/settings/deviceinfo/HardwareInfoDialogFragment.java b/src/com/android/settings/deviceinfo/HardwareInfoDialogFragment.java
index 26f1ac2..6169b44 100644
--- a/src/com/android/settings/deviceinfo/HardwareInfoDialogFragment.java
+++ b/src/com/android/settings/deviceinfo/HardwareInfoDialogFragment.java
@@ -23,14 +23,12 @@
import android.os.SystemProperties;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
-import android.util.FeatureFlagUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
-import com.android.settings.core.FeatureFlags;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
public class HardwareInfoDialogFragment extends InstrumentedDialogFragment {
@@ -59,12 +57,7 @@
DeviceModelPreferenceController.getDeviceModel());
// Serial number
- if (FeatureFlagUtils.isEnabled(getContext(), FeatureFlags.DEVICE_INFO_V2)) {
- setText(content, R.id.serial_number_label, R.id.serial_number_value, getSerialNumber());
- } else {
- content.findViewById(R.id.serial_number_label).setVisibility(View.GONE);
- content.findViewById(R.id.serial_number_value).setVisibility(View.GONE);
- }
+ setText(content, R.id.serial_number_label, R.id.serial_number_value, getSerialNumber());
// Hardware rev
setText(content, R.id.hardware_rev_label, R.id.hardware_rev_value,
diff --git a/src/com/android/settings/deviceinfo/ImeiInfoPreferenceController.java b/src/com/android/settings/deviceinfo/ImeiInfoPreferenceController.java
deleted file mode 100644
index 456dbfc..0000000
--- a/src/com/android/settings/deviceinfo/ImeiInfoPreferenceController.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.settings.deviceinfo;
-
-import android.content.Context;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.deviceinfo.imei.ImeiInfoPreferenceControllerV2;
-import com.android.settingslib.deviceinfo.AbstractSimStatusImeiInfoPreferenceController;
-
-/**
- * deprecated in favour of {@link ImeiInfoPreferenceControllerV2}
- */
-@Deprecated
-public class ImeiInfoPreferenceController extends AbstractSimStatusImeiInfoPreferenceController
- implements PreferenceControllerMixin {
-
- private static final String KEY_IMEI_INFO = "imei_info";
-
- public ImeiInfoPreferenceController(Context context) {
- super(context);
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_IMEI_INFO;
- }
-}
diff --git a/src/com/android/settings/deviceinfo/ImeiInformation.java b/src/com/android/settings/deviceinfo/ImeiInformation.java
deleted file mode 100644
index 9f38f1b..0000000
--- a/src/com/android/settings/deviceinfo/ImeiInformation.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2014 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.deviceinfo;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.TextUtils;
-
-import android.text.style.TtsSpan;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.PhoneFactory;
-import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.deviceinfo.imei.ImeiInfoPreferenceControllerV2;
-
-/**
- * deprecated in favor of {@link ImeiInfoPreferenceControllerV2}
- */
-@Deprecated
-public class ImeiInformation extends SettingsPreferenceFragment {
-
- private static final String KEY_PRL_VERSION = "prl_version";
- private static final String KEY_MIN_NUMBER = "min_number";
- private static final String KEY_MEID_NUMBER = "meid_number";
- private static final String KEY_ICC_ID = "icc_id";
- private static final String KEY_IMEI = "imei";
- private static final String KEY_IMEI_SV = "imei_sv";
-
- private SubscriptionManager mSubscriptionManager;
- private boolean isMultiSIM = false;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mSubscriptionManager = SubscriptionManager.from(getContext());
- final TelephonyManager telephonyManager =
- (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
- initPreferenceScreen(telephonyManager.getSimCount());
- }
-
- // Since there are multiple phone for dsds, therefore need to show information for different
- // phones.
- private void initPreferenceScreen(int slotCount) {
- isMultiSIM = (slotCount > 1);
- for (int slotId = 0; slotId < slotCount; slotId ++) {
- addPreferencesFromResource(R.xml.device_info_phone_status);
- setPreferenceValue(slotId);
- setNewKey(slotId);
- }
- }
-
- private void setPreferenceValue(int phoneId) {
- final Phone phone = PhoneFactory.getPhone(phoneId);
-
- if (phone != null) {
- if (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
- setSummaryText(KEY_MEID_NUMBER, phone.getMeid());
- setSummaryText(KEY_MIN_NUMBER, phone.getCdmaMin());
-
- if (getResources().getBoolean(R.bool.config_msid_enable)) {
- findPreference(KEY_MIN_NUMBER).setTitle(R.string.status_msid_number);
- }
-
- setSummaryText(KEY_PRL_VERSION, phone.getCdmaPrlVersion());
-
- if (phone.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE) {
- // Show ICC ID and IMEI for LTE device
- setSummaryText(KEY_ICC_ID, phone.getIccSerialNumber());
- setSummaryTextAsDigit(KEY_IMEI, phone.getImei());
- setSummaryTextAsDigit(KEY_IMEI_SV, phone.getDeviceSvn());
- } else {
- // device is not GSM/UMTS, do not display GSM/UMTS features
- // check Null in case no specified preference in overlay xml
- removePreferenceFromScreen(KEY_IMEI_SV);
- removePreferenceFromScreen(KEY_IMEI);
- removePreferenceFromScreen(KEY_ICC_ID);
- }
- } else {
- setSummaryTextAsDigit(KEY_IMEI, phone.getImei());
- setSummaryTextAsDigit(KEY_IMEI_SV, phone.getDeviceSvn());
- // device is not CDMA, do not display CDMA features
- // check Null in case no specified preference in overlay xml
- removePreferenceFromScreen(KEY_PRL_VERSION);
- removePreferenceFromScreen(KEY_MEID_NUMBER);
- removePreferenceFromScreen(KEY_MIN_NUMBER);
- removePreferenceFromScreen(KEY_ICC_ID);
- }
- }
- }
-
- // Modify the preference key with prefix "_", so new added information preference can be set
- // related phone information.
- private void setNewKey(int slotId) {
- final PreferenceScreen prefScreen = getPreferenceScreen();
- final int count = prefScreen.getPreferenceCount();
- for (int i = 0; i < count; i++) {
- Preference pref = prefScreen.getPreference(i);
- String key = pref.getKey();
- if (!key.startsWith("_")){
- key = "_" + key + String.valueOf(slotId);
- pref.setKey(key);
- updateTitle(pref, slotId);
- }
- }
- }
-
- private void updateTitle(Preference pref, int slotId) {
- if (pref != null) {
- String title = pref.getTitle().toString();
- if (isMultiSIM) {
- // Slot starts from 1, slotId starts from 0 so plus 1
- title += " " + getResources().getString(R.string.slot_number, slotId + 1);
- }
- pref.setTitle(title);
- }
- }
-
- private void setSummaryText(String key, String text) {
- setSummaryText(key, text, false /* forceDigit */);
- }
-
- private void setSummaryTextAsDigit(String key, String text) {
- setSummaryText(key, text, true /* forceDigit */);
- }
-
- private void setSummaryText(String key, CharSequence text, boolean forceDigit) {
- final Preference preference = findPreference(key);
-
- if (TextUtils.isEmpty(text)) {
- text = getResources().getString(R.string.device_info_default);
- } else if (forceDigit && TextUtils.isDigitsOnly(text)) {
- final Spannable spannable = new SpannableStringBuilder(text);
- final TtsSpan span = new TtsSpan.DigitsBuilder(text.toString()).build();
- spannable.setSpan(span, 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- text = spannable;
- }
-
- if (preference != null) {
- preference.setSummary(text);
- }
- }
-
- /**
- * Removes the specified preference, if it exists.
- * @param key the key for the Preference item
- */
- private void removePreferenceFromScreen(String key) {
- final Preference preference = findPreference(key);
- if (preference != null) {
- getPreferenceScreen().removePreference(preference);
- }
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.DEVICEINFO_IMEI_INFORMATION;
- }
-}
diff --git a/src/com/android/settings/deviceinfo/SecurityPatchPreferenceController.java b/src/com/android/settings/deviceinfo/SecurityPatchPreferenceController.java
deleted file mode 100644
index 9b0120e..0000000
--- a/src/com/android/settings/deviceinfo/SecurityPatchPreferenceController.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.
- */
-package com.android.settings.deviceinfo;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.deviceinfo.firmwareversion.SecurityPatchLevelDialogController;
-import com.android.settingslib.DeviceInfoUtils;
-import com.android.settingslib.core.AbstractPreferenceController;
-
-/**
- * deprecated in favor of {@link SecurityPatchLevelDialogController}
- */
-@Deprecated
-public class SecurityPatchPreferenceController extends AbstractPreferenceController implements
- PreferenceControllerMixin {
-
- private static final String KEY_SECURITY_PATCH = "security_patch";
- private static final String TAG = "SecurityPatchPref";
-
- private final String mPatch;
- private final PackageManager mPackageManager;
-
- public SecurityPatchPreferenceController(Context context) {
- super(context);
- mPackageManager = mContext.getPackageManager();
- mPatch = DeviceInfoUtils.getSecurityPatch();
- }
-
- @Override
- public boolean isAvailable() {
- return !TextUtils.isEmpty(mPatch);
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_SECURITY_PATCH;
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- final Preference pref = screen.findPreference(KEY_SECURITY_PATCH);
- if (pref != null) {
- pref.setSummary(mPatch);
- }
- }
-
- @Override
- public boolean handlePreferenceTreeClick(Preference preference) {
- if (!TextUtils.equals(preference.getKey(), KEY_SECURITY_PATCH)) {
- return false;
- }
- if (mPackageManager.queryIntentActivities(preference.getIntent(), 0).isEmpty()) {
- // Don't send out the intent to stop crash
- Log.w(TAG, "Stop click action on " + KEY_SECURITY_PATCH + ": "
- + "queryIntentActivities() returns empty");
- return true;
- }
- return false;
- }
-}
diff --git a/src/com/android/settings/deviceinfo/SerialNumberPreferenceController.java b/src/com/android/settings/deviceinfo/SerialNumberPreferenceController.java
deleted file mode 100644
index e466bbf..0000000
--- a/src/com/android/settings/deviceinfo/SerialNumberPreferenceController.java
+++ /dev/null
@@ -1,39 +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.deviceinfo;
-
-import android.content.Context;
-import android.os.Build;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.deviceinfo.AbstractSerialNumberPreferenceController;
-
-/**
- * Preference controller for displaying device serial number. Wraps {@link Build#getSerial()}.
- *
- * deprecated because this preference is no longer used in About Phone V2
- */
-@Deprecated
-public class SerialNumberPreferenceController extends
- AbstractSerialNumberPreferenceController implements
- PreferenceControllerMixin {
- public SerialNumberPreferenceController(Context context) {
- super(context);
- }
-
- // This space intentionally left blank
-}
diff --git a/src/com/android/settings/deviceinfo/SimStatus.java b/src/com/android/settings/deviceinfo/SimStatus.java
deleted file mode 100644
index dad4419..0000000
--- a/src/com/android/settings/deviceinfo/SimStatus.java
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * Copyright (C) 2014 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.deviceinfo;
-
-import static android.content.Context.CARRIER_CONFIG_SERVICE;
-import static android.content.Context.TELEPHONY_SERVICE;
-
-import android.Manifest;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.os.PersistableBundle;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.support.v7.preference.Preference;
-import android.telephony.CarrierConfigManager;
-import android.telephony.CellBroadcastMessage;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ListView;
-import android.widget.TabHost;
-import android.widget.TabHost.OnTabChangeListener;
-import android.widget.TabHost.TabContentFactory;
-import android.widget.TabHost.TabSpec;
-import android.widget.TabWidget;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneConstantConversions;
-import com.android.internal.telephony.PhoneFactory;
-import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.Utils;
-import com.android.settingslib.DeviceInfoUtils;
-
-import java.util.List;
-
-
-/**
- * Display the following information
- * # Phone Number
- * # Network
- * # Roaming
- * # Device Id (IMEI in GSM and MEID in CDMA)
- * # Network type
- * # Operator info (area update info cell broadcast)
- * # Signal Strength
- *
- * deprecated in favor of {@link com.android.settings.deviceinfo.simstatus.SimStatusDialogFragment}
- */
-@Deprecated
-public class SimStatus extends SettingsPreferenceFragment {
- private static final String TAG = "SimStatus";
-
- private static final String KEY_DATA_STATE = "data_state";
- private static final String KEY_SERVICE_STATE = "service_state";
- private static final String KEY_OPERATOR_NAME = "operator_name";
- private static final String KEY_ROAMING_STATE = "roaming_state";
- private static final String KEY_NETWORK_TYPE = "network_type";
- private static final String KEY_LATEST_AREA_INFO = "latest_area_info";
- private static final String KEY_PHONE_NUMBER = "number";
- private static final String KEY_SIGNAL_STRENGTH = "signal_strength";
- private static final String KEY_IMEI = "imei";
- private static final String KEY_IMEI_SV = "imei_sv";
- private static final String KEY_ICCID = "iccid";
-
- static private final String CB_AREA_INFO_RECEIVED_ACTION =
- "com.android.cellbroadcastreceiver.CB_AREA_INFO_RECEIVED";
-
- static private final String GET_LATEST_CB_AREA_INFO_ACTION =
- "com.android.cellbroadcastreceiver.GET_LATEST_CB_AREA_INFO";
-
- static private final String CELL_BROADCAST_RECEIVER_APP = "com.android.cellbroadcastreceiver";
-
- private TelephonyManager mTelephonyManager;
- private CarrierConfigManager mCarrierConfigManager;
- private Phone mPhone = null;
- private Resources mRes;
- private Preference mSignalStrength;
- private SubscriptionInfo mSir;
- private boolean mShowLatestAreaInfo;
- private boolean mShowICCID;
-
- // Default summary for items
- private String mDefaultText;
-
- private TabHost mTabHost;
- private TabWidget mTabWidget;
- private ListView mListView;
- private List<SubscriptionInfo> mSelectableSubInfos;
-
- private PhoneStateListener mPhoneStateListener;
-
- // Once the cell broadcast configuration is moved into telephony framework,
- private final BroadcastReceiver mAreaInfoReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (CB_AREA_INFO_RECEIVED_ACTION.equals(action)) {
- Bundle extras = intent.getExtras();
- if (extras == null) {
- return;
- }
- CellBroadcastMessage cbMessage = (CellBroadcastMessage) extras.get("message");
- if (cbMessage != null && mSir.getSubscriptionId() == cbMessage.getSubId()) {
- String latestAreaInfo = cbMessage.getMessageBody();
- updateAreaInfo(latestAreaInfo);
- }
- }
- }
- };
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- mTelephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
- mCarrierConfigManager = (CarrierConfigManager) getSystemService(CARRIER_CONFIG_SERVICE);
-
- mSelectableSubInfos = SubscriptionManager.from(getContext())
- .getActiveSubscriptionInfoList();
-
- addPreferencesFromResource(R.xml.device_info_sim_status);
-
- mRes = getResources();
- mDefaultText = mRes.getString(R.string.device_info_default);
- // Note - missing in zaku build, be careful later...
- mSignalStrength = findPreference(KEY_SIGNAL_STRENGTH);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- if (mSelectableSubInfos == null) {
- mSir = null;
- } else {
- mSir = mSelectableSubInfos.size() > 0 ? mSelectableSubInfos.get(0) : null;
-
- if (mSelectableSubInfos.size() > 1) {
- View view = inflater.inflate(R.layout.icc_lock_tabs, container, false);
- final ViewGroup prefs_container = (ViewGroup) view.findViewById(
- R.id.prefs_container);
- Utils.prepareCustomPreferencesList(container, view, prefs_container, false);
- View prefs = super.onCreateView(inflater, prefs_container, savedInstanceState);
- prefs_container.addView(prefs);
-
- mTabHost = (TabHost) view.findViewById(android.R.id.tabhost);
- mTabWidget = (TabWidget) view.findViewById(android.R.id.tabs);
- mListView = (ListView) view.findViewById(android.R.id.list);
-
- mTabHost.setup();
- mTabHost.setOnTabChangedListener(mTabListener);
- mTabHost.clearAllTabs();
-
- for (int i = 0; i < mSelectableSubInfos.size(); i++) {
- mTabHost.addTab(buildTabSpec(String.valueOf(i),
- String.valueOf(mSelectableSubInfos.get(i).getDisplayName())));
- }
- return view;
- }
- }
- return super.onCreateView(inflater, container, savedInstanceState);
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- updatePhoneInfos();
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.DEVICEINFO_SIM_STATUS;
- }
-
- @Override
- public void onResume() {
- super.onResume();
- if (mPhone != null) {
- updatePreference();
-
- updateSignalStrength(mPhone.getSignalStrength());
- updateServiceState(mPhone.getServiceState());
- updateDataState();
- mTelephonyManager.listen(mPhoneStateListener,
- PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
- | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
- | PhoneStateListener.LISTEN_SERVICE_STATE);
- if (mShowLatestAreaInfo) {
- getContext().registerReceiver(mAreaInfoReceiver,
- new IntentFilter(CB_AREA_INFO_RECEIVED_ACTION),
- Manifest.permission.RECEIVE_EMERGENCY_BROADCAST, null);
- // Ask CellBroadcastReceiver to broadcast the latest area info received
- Intent getLatestIntent = new Intent(GET_LATEST_CB_AREA_INFO_ACTION);
- getLatestIntent.setPackage(CELL_BROADCAST_RECEIVER_APP);
- getContext().sendBroadcastAsUser(getLatestIntent, UserHandle.ALL,
- Manifest.permission.RECEIVE_EMERGENCY_BROADCAST);
- }
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
-
- if (mPhone != null) {
- mTelephonyManager.listen(mPhoneStateListener,
- PhoneStateListener.LISTEN_NONE);
- }
- if (mShowLatestAreaInfo) {
- getContext().unregisterReceiver(mAreaInfoReceiver);
- }
- }
-
- /**
- * Removes the specified preference, if it exists.
- * @param key the key for the Preference item
- */
- private void removePreferenceFromScreen(String key) {
- Preference pref = findPreference(key);
- if (pref != null) {
- getPreferenceScreen().removePreference(pref);
- }
- }
-
- private void setSummaryText(String key, String text) {
- if (TextUtils.isEmpty(text)) {
- text = mDefaultText;
- }
- // some preferences may be missing
- final Preference preference = findPreference(key);
- if (preference != null) {
- preference.setSummary(text);
- }
- }
-
- private void updateNetworkType() {
- // Whether EDGE, UMTS, etc...
- String networktype = null;
- final int subId = mSir.getSubscriptionId();
- final int actualDataNetworkType = mTelephonyManager.getDataNetworkType(
- mSir.getSubscriptionId());
- final int actualVoiceNetworkType = mTelephonyManager.getVoiceNetworkType(
- mSir.getSubscriptionId());
- if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualDataNetworkType) {
- networktype = mTelephonyManager.getNetworkTypeName(actualDataNetworkType);
- } else if (TelephonyManager.NETWORK_TYPE_UNKNOWN != actualVoiceNetworkType) {
- networktype = mTelephonyManager.getNetworkTypeName(actualVoiceNetworkType);
- }
-
- boolean show4GForLTE = false;
- try {
- Context con = getActivity().createPackageContext("com.android.systemui", 0);
- int id = con.getResources().getIdentifier("config_show4GForLTE",
- "bool", "com.android.systemui");
- show4GForLTE = con.getResources().getBoolean(id);
- } catch (NameNotFoundException e) {
- Log.e(TAG, "NameNotFoundException for show4GFotLTE");
- }
-
- if (networktype != null && networktype.equals("LTE") && show4GForLTE) {
- networktype = "4G";
- }
- setSummaryText(KEY_NETWORK_TYPE, networktype);
- }
-
- private void updateDataState() {
- final int state =
- PhoneConstantConversions.convertDataState(mPhone.getDataConnectionState());
-
- String display = mRes.getString(R.string.radioInfo_unknown);
-
- switch (state) {
- case TelephonyManager.DATA_CONNECTED:
- display = mRes.getString(R.string.radioInfo_data_connected);
- break;
- case TelephonyManager.DATA_SUSPENDED:
- display = mRes.getString(R.string.radioInfo_data_suspended);
- break;
- case TelephonyManager.DATA_CONNECTING:
- display = mRes.getString(R.string.radioInfo_data_connecting);
- break;
- case TelephonyManager.DATA_DISCONNECTED:
- display = mRes.getString(R.string.radioInfo_data_disconnected);
- break;
- }
-
- setSummaryText(KEY_DATA_STATE, display);
- }
-
- private void updateServiceState(ServiceState serviceState) {
- final int state = serviceState.getState();
- String display = mRes.getString(R.string.radioInfo_unknown);
-
- switch (state) {
- case ServiceState.STATE_IN_SERVICE:
- display = mRes.getString(R.string.radioInfo_service_in);
- break;
- case ServiceState.STATE_OUT_OF_SERVICE:
- // Set signal strength to 0 when service state is STATE_OUT_OF_SERVICE
- mSignalStrength.setSummary("0");
- case ServiceState.STATE_EMERGENCY_ONLY:
- // Set summary string of service state to radioInfo_service_out when
- // service state is both STATE_OUT_OF_SERVICE & STATE_EMERGENCY_ONLY
- display = mRes.getString(R.string.radioInfo_service_out);
- break;
- case ServiceState.STATE_POWER_OFF:
- display = mRes.getString(R.string.radioInfo_service_off);
- // Also set signal strength to 0
- mSignalStrength.setSummary("0");
- break;
- }
-
- setSummaryText(KEY_SERVICE_STATE, display);
-
- if (serviceState.getRoaming()) {
- setSummaryText(KEY_ROAMING_STATE, mRes.getString(R.string.radioInfo_roaming_in));
- } else {
- setSummaryText(KEY_ROAMING_STATE, mRes.getString(R.string.radioInfo_roaming_not));
- }
- setSummaryText(KEY_OPERATOR_NAME, serviceState.getOperatorAlphaLong());
- }
-
- private void updateAreaInfo(String areaInfo) {
- if (areaInfo != null) {
- setSummaryText(KEY_LATEST_AREA_INFO, areaInfo);
- }
- }
-
- void updateSignalStrength(SignalStrength signalStrength) {
- if (mSignalStrength != null) {
- final int state = mPhone.getServiceState().getState();
-
- if ((ServiceState.STATE_OUT_OF_SERVICE == state) ||
- (ServiceState.STATE_POWER_OFF == state)) {
- mSignalStrength.setSummary("0");
- return;
- }
-
- int signalDbm = signalStrength.getDbm();
- int signalAsu = signalStrength.getAsuLevel();
-
- if (-1 == signalDbm) {
- signalDbm = 0;
- }
-
- if (-1 == signalAsu) {
- signalAsu = 0;
- }
-
- mSignalStrength.setSummary(mRes.getString(R.string.sim_signal_strength,
- signalDbm, signalAsu));
- }
- }
-
- private void updatePreference() {
- if (mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA) {
- mShowLatestAreaInfo = Resources.getSystem().getBoolean(
- com.android.internal.R.bool.config_showAreaUpdateInfoSettings);
- }
- PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(
- mSir.getSubscriptionId());
- mShowICCID = carrierConfig.getBoolean(
- CarrierConfigManager.KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL);
-
-
- // If formattedNumber is null or empty, it'll display as "Unknown".
- setSummaryText(KEY_PHONE_NUMBER,
- DeviceInfoUtils.getFormattedPhoneNumber(getContext(), mSir));
- setSummaryText(KEY_IMEI, mPhone.getImei());
- setSummaryText(KEY_IMEI_SV, mPhone.getDeviceSvn());
-
- if (!mShowICCID) {
- removePreferenceFromScreen(KEY_ICCID);
- } else {
- // Get ICCID, which is SIM serial number
- String iccid = mTelephonyManager.getSimSerialNumber(mSir.getSubscriptionId());
- setSummaryText(KEY_ICCID, iccid);
- }
-
- if (!mShowLatestAreaInfo) {
- removePreferenceFromScreen(KEY_LATEST_AREA_INFO);
- }
-
- boolean hideSignalStrength = carrierConfig.getBoolean(
- CarrierConfigManager.KEY_HIDE_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL);
- if (hideSignalStrength) {
- removePreferenceFromScreen(KEY_SIGNAL_STRENGTH);
- }
- }
-
- private void updatePhoneInfos() {
- if (mSir != null) {
- // TODO: http://b/23763013
- final Phone phone = PhoneFactory.getPhone(SubscriptionManager.getPhoneId(
- mSir.getSubscriptionId()));
- if (UserManager.get(getContext()).isAdminUser()
- && SubscriptionManager.isValidSubscriptionId(mSir.getSubscriptionId())) {
- if (phone == null) {
- Log.e(TAG, "Unable to locate a phone object for the given Subscription ID.");
- return;
- }
-
- mPhone = phone;
- // To avoid register multiple listeners when user changes the tab.
- if (mPhoneStateListener != null && mTelephonyManager != null) {
- mTelephonyManager.listen(mPhoneStateListener,
- PhoneStateListener.LISTEN_NONE);
- mPhoneStateListener = null;
- }
- mPhoneStateListener = new PhoneStateListener(mSir.getSubscriptionId()) {
- @Override
- public void onDataConnectionStateChanged(int state) {
- updateDataState();
- updateNetworkType();
- }
-
- @Override
- public void onSignalStrengthsChanged(SignalStrength signalStrength) {
- updateSignalStrength(signalStrength);
- }
-
- @Override
- public void onServiceStateChanged(ServiceState serviceState) {
- updateServiceState(serviceState);
- }
- };
- }
- }
- }
- private OnTabChangeListener mTabListener = new OnTabChangeListener() {
- @Override
- public void onTabChanged(String tabId) {
- final int slotId = Integer.parseInt(tabId);
- mSir = mSelectableSubInfos.get(slotId);
-
- // The User has changed tab; update the SIM information.
- updatePhoneInfos();
- mTelephonyManager.listen(mPhoneStateListener,
- PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
- | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
- | PhoneStateListener.LISTEN_SERVICE_STATE);
- updateDataState();
- updateNetworkType();
- updatePreference();
- }
- };
-
- private TabContentFactory mEmptyTabContent = new TabContentFactory() {
- @Override
- public View createTabContent(String tag) {
- return new View(mTabHost.getContext());
- }
- };
-
- private TabSpec buildTabSpec(String tag, String title) {
- return mTabHost.newTabSpec(tag).setIndicator(title).setContent(
- mEmptyTabContent);
- }
-}
diff --git a/src/com/android/settings/deviceinfo/SimStatusPreferenceController.java b/src/com/android/settings/deviceinfo/SimStatusPreferenceController.java
deleted file mode 100644
index ca531ea5..0000000
--- a/src/com/android/settings/deviceinfo/SimStatusPreferenceController.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.settings.deviceinfo;
-
-import android.content.Context;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.deviceinfo.simstatus.SimStatusPreferenceControllerV2;
-import com.android.settingslib.deviceinfo.AbstractSimStatusImeiInfoPreferenceController;
-
-/**
- * deprecated in favor of {@link SimStatusPreferenceControllerV2}
- */
-@Deprecated
-public class SimStatusPreferenceController extends AbstractSimStatusImeiInfoPreferenceController
- implements PreferenceControllerMixin {
-
- private static final String KEY_SIM_STATUS = "sim_status";
-
- public SimStatusPreferenceController(Context context) {
- super(context);
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_SIM_STATUS;
- }
-}
diff --git a/src/com/android/settings/deviceinfo/Status.java b/src/com/android/settings/deviceinfo/Status.java
deleted file mode 100644
index 15ad5cf..0000000
--- a/src/com/android/settings/deviceinfo/Status.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2008 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.deviceinfo;
-
-import android.content.Context;
-import android.provider.SearchIndexableResource;
-
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settings.DeviceInfoSettings;
-import com.android.settings.R;
-import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Fragment for showing device hardware info, such as MAC addresses and serial numbers
- * Deprecated in About Phone V2
- * Information on this page is available in {@link DeviceInfoSettings}
- */
-@Deprecated
-public class Status extends DashboardFragment {
-
- private static final String TAG = "DeviceStatus";
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.DEVICEINFO_STATUS;
- }
-
- @Override
- protected String getLogTag() {
- return TAG;
- }
-
- @Override
- protected int getPreferenceScreenResId() {
- return R.xml.device_info_status;
- }
-
- @Override
- protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
- return buildPreferenceControllers(context, getLifecycle());
- }
-
- private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
- Lifecycle lifecycle) {
- final List<AbstractPreferenceController> controllers = new ArrayList<>();
- controllers.add(new SerialNumberPreferenceController(context));
- controllers.add(new UptimePreferenceController(context, lifecycle));
- controllers.add(new BluetoothAddressPreferenceController(context, lifecycle));
- controllers.add(new IpAddressPreferenceController(context, lifecycle));
- controllers.add(new WifiMacAddressPreferenceController(context, lifecycle));
- controllers.add(new ImsStatusPreferenceController(context, lifecycle));
- controllers.add(new SimStatusPreferenceController(context));
- controllers.add(new ImeiInfoPreferenceController(context));
- controllers.add(new BatteryInfoPreferenceController(context, lifecycle));
- return controllers;
- }
-
- /**
- * For Search.
- */
- public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider() {
-
- @Override
- public List<SearchIndexableResource> getXmlResourcesToIndex(
- Context context, boolean enabled) {
- final SearchIndexableResource sir = new SearchIndexableResource(context);
- sir.xmlResId = R.xml.device_info_status;
- return Arrays.asList(sir);
- }
-
- @Override
- public List<AbstractPreferenceController> getPreferenceControllers(Context
- context) {
- return buildPreferenceControllers(context, null /* lifecycle */);
- }
- };
-}
diff --git a/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java b/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java
index d8a64a8..92c33d8 100644
--- a/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java
@@ -30,11 +30,9 @@
import com.android.settings.R;
import com.android.settings.Utils;
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settings.core.BasePreferenceController;
-public class SystemUpdatePreferenceController extends AbstractPreferenceController implements
- PreferenceControllerMixin {
+public class SystemUpdatePreferenceController extends BasePreferenceController {
private static final String TAG = "SysUpdatePrefContr";
@@ -42,19 +40,16 @@
private final UserManager mUm;
- public SystemUpdatePreferenceController(Context context, UserManager um) {
- super(context);
- mUm = um;
+ public SystemUpdatePreferenceController(Context context) {
+ super(context, KEY_SYSTEM_UPDATE_SETTINGS);
+ mUm = UserManager.get(context);
}
@Override
- public boolean isAvailable() {
- return mUm.isAdminUser();
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_SYSTEM_UPDATE_SETTINGS;
+ public int getAvailabilityStatus() {
+ return mUm.isAdminUser()
+ ? AVAILABLE
+ : DISABLED_UNSUPPORTED;
}
@Override
@@ -62,14 +57,14 @@
super.displayPreference(screen);
if (isAvailable()) {
Utils.updatePreferenceToSpecificActivityOrRemove(mContext, screen,
- KEY_SYSTEM_UPDATE_SETTINGS,
+ getPreferenceKey(),
Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
}
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
- if (KEY_SYSTEM_UPDATE_SETTINGS.equals(preference.getKey())) {
+ if (TextUtils.equals(getPreferenceKey(), preference.getKey())) {
CarrierConfigManager configManager =
(CarrierConfigManager) mContext.getSystemService(CARRIER_CONFIG_SERVICE);
PersistableBundle b = configManager.getConfig();
@@ -108,4 +103,4 @@
mContext.getApplicationContext().sendBroadcast(intent);
}
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/deviceinfo/UptimePreferenceController.java b/src/com/android/settings/deviceinfo/UptimePreferenceController.java
deleted file mode 100644
index c25f984..0000000
--- a/src/com/android/settings/deviceinfo/UptimePreferenceController.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.settings.deviceinfo;
-
-import android.content.Context;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settings.fuelgauge.PowerUsageSummary;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.deviceinfo.AbstractUptimePreferenceController;
-
-/**
- * Concrete subclass of uptime preference controller
- *
- * Deprecated in About Phone V2
- * Information in this preference is available in {@link PowerUsageSummary}
- */
-@Deprecated
-public class UptimePreferenceController extends AbstractUptimePreferenceController
- implements PreferenceControllerMixin {
- public UptimePreferenceController(Context context, Lifecycle lifecycle) {
- super(context, lifecycle);
- }
-
- // This space intentionally left blank
-}
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
index 15ca87b..35b8bd1 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogController.java
@@ -68,6 +68,8 @@
@VisibleForTesting
final static int SERVICE_STATE_VALUE_ID = R.id.service_state_value;
@VisibleForTesting
+ final static int SIGNAL_STRENGTH_LABEL_ID = R.id.signal_strength_label;
+ @VisibleForTesting
final static int SIGNAL_STRENGTH_VALUE_ID = R.id.signal_strength_value;
@VisibleForTesting
final static int CELLULAR_NETWORK_TYPE_VALUE_ID = R.id.network_type_value;
@@ -262,6 +264,21 @@
}
private void updateSignalStrength(SignalStrength signalStrength) {
+ final int subscriptionId = mSubscriptionInfo.getSubscriptionId();
+ final PersistableBundle carrierConfig =
+ mCarrierConfigManager.getConfigForSubId(subscriptionId);
+ // by default we show the signal strength
+ boolean showSignalStrength = true;
+ if (carrierConfig != null) {
+ showSignalStrength = carrierConfig.getBoolean(
+ CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL);
+ }
+ if (!showSignalStrength) {
+ mDialog.removeSettingFromScreen(SIGNAL_STRENGTH_LABEL_ID);
+ mDialog.removeSettingFromScreen(SIGNAL_STRENGTH_VALUE_ID);
+ return;
+ }
+
final int state = getCurrentServiceState().getState();
if ((ServiceState.STATE_OUT_OF_SERVICE == state) ||
@@ -327,9 +344,14 @@
private void updateIccidNumber() {
final int subscriptionId = mSubscriptionInfo.getSubscriptionId();
- final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(subscriptionId);
- final boolean showIccId = carrierConfig.getBoolean(
- CarrierConfigManager.KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL);
+ final PersistableBundle carrierConfig =
+ mCarrierConfigManager.getConfigForSubId(subscriptionId);
+ // do not show iccid by default
+ boolean showIccId = false;
+ if (carrierConfig != null) {
+ showIccId = carrierConfig.getBoolean(
+ CarrierConfigManager.KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL);
+ }
if (!showIccId) {
mDialog.removeSettingFromScreen(ICCID_INFO_LABEL_ID);
mDialog.removeSettingFromScreen(ICCID_INFO_VALUE_ID);
diff --git a/src/com/android/settings/display/ThemePreferenceController.java b/src/com/android/settings/display/ThemePreferenceController.java
index 3bb58b1..d1341dd74 100644
--- a/src/com/android/settings/display/ThemePreferenceController.java
+++ b/src/com/android/settings/display/ThemePreferenceController.java
@@ -125,7 +125,7 @@
private boolean isChangeableOverlay(String packageName) {
try {
PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
- return pi != null && !pi.isStaticOverlay;
+ return pi != null && !pi.isStaticOverlayPackage();
} catch (PackageManager.NameNotFoundException e) {
return false;
}
diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
index f7a2b9a..d0f4080 100644
--- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
@@ -20,16 +20,18 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.PowerManager;
import android.support.annotation.VisibleForTesting;
import com.android.settings.Utils;
/**
* Use this broadcastReceiver to listen to the battery change, and it will invoke
- * {@link OnBatteryChangedListener} if any of the following happens:
+ * {@link OnBatteryChangedListener} if any of the followings has been changed:
*
- * 1. Battery level has been changed
- * 2. Battery status has been changed
+ * 1. Battery level(e.g. 100%->99%)
+ * 2. Battery status(e.g. plugged->unplugged)
+ * 3. Battery saver(e.g. off->on)
*/
public class BatteryBroadcastReceiver extends BroadcastReceiver {
@@ -58,8 +60,11 @@
}
public void register() {
- final Intent intent = mContext.registerReceiver(this,
- new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+
+ final Intent intent = mContext.registerReceiver(this, intentFilter);
updateBatteryStatus(intent, true /* forceUpdate */);
}
@@ -68,15 +73,18 @@
}
private void updateBatteryStatus(Intent intent, boolean forceUpdate) {
- if (intent != null && mBatteryListener != null && Intent.ACTION_BATTERY_CHANGED.equals(
- intent.getAction())) {
- String batteryLevel = Utils.getBatteryPercentage(intent);
- String batteryStatus = Utils.getBatteryStatus(
- mContext.getResources(), intent);
- if (forceUpdate || !batteryLevel.equals(mBatteryLevel) || !batteryStatus.equals(
- mBatteryStatus)) {
- mBatteryLevel = batteryLevel;
- mBatteryStatus = batteryStatus;
+ if (intent != null && mBatteryListener != null) {
+ if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
+ final String batteryLevel = Utils.getBatteryPercentage(intent);
+ final String batteryStatus = Utils.getBatteryStatus(
+ mContext.getResources(), intent);
+ if (forceUpdate || !batteryLevel.equals(mBatteryLevel) || !batteryStatus.equals(
+ mBatteryStatus)) {
+ mBatteryLevel = batteryLevel;
+ mBatteryStatus = batteryStatus;
+ mBatteryListener.onBatteryChanged();
+ }
+ } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
mBatteryListener.onBatteryChanged();
}
}
diff --git a/src/com/android/settings/gestures/GesturesSettingPreferenceController.java b/src/com/android/settings/gestures/GesturesSettingPreferenceController.java
index d1b47b2..819b128 100644
--- a/src/com/android/settings/gestures/GesturesSettingPreferenceController.java
+++ b/src/com/android/settings/gestures/GesturesSettingPreferenceController.java
@@ -23,27 +23,26 @@
import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.List;
-public class GesturesSettingPreferenceController extends AbstractPreferenceController
- implements PreferenceControllerMixin {
-
- private static final String KEY_GESTURES_SETTINGS = "gesture_settings";
-
+public class GesturesSettingPreferenceController extends BasePreferenceController {
private final AssistGestureFeatureProvider mFeatureProvider;
private List<AbstractPreferenceController> mGestureControllers;
+ private static final String KEY_GESTURES_SETTINGS = "gesture_settings";
+
public GesturesSettingPreferenceController(Context context) {
- super(context);
+ super(context, KEY_GESTURES_SETTINGS);
mFeatureProvider = FeatureFactory.getFactory(context).getAssistGestureFeatureProvider();
}
@Override
- public boolean isAvailable() {
+ public int getAvailabilityStatus() {
if (mGestureControllers == null) {
mGestureControllers = GestureSettings.buildPreferenceControllers(mContext,
null /* lifecycle */, new AmbientDisplayConfiguration(mContext));
@@ -52,12 +51,9 @@
for (AbstractPreferenceController controller : mGestureControllers) {
isAvailable = isAvailable || controller.isAvailable();
}
- return isAvailable;
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_GESTURES_SETTINGS;
+ return isAvailable
+ ? AVAILABLE
+ : DISABLED_UNSUPPORTED;
}
@Override
@@ -83,5 +79,4 @@
}
preference.setSummary(summary);
}
-
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/location/LocationMode.java b/src/com/android/settings/location/LocationMode.java
index 34f082b..5931f9e 100644
--- a/src/com/android/settings/location/LocationMode.java
+++ b/src/com/android/settings/location/LocationMode.java
@@ -95,6 +95,11 @@
}
@Override
+ protected boolean isPageSearchEnabled(Context context) {
+ return context.getResources().getBoolean(R.bool.config_location_mode_available);
+ }
+
+ @Override
public List<AbstractPreferenceController> getPreferenceControllers(Context
context) {
return buildPreferenceControllers(context, null /* lifecycle */);
diff --git a/src/com/android/settings/location/RecentLocationRequestPreferenceController.java b/src/com/android/settings/location/RecentLocationRequestPreferenceController.java
index 8c4fa579..461f6e3 100644
--- a/src/com/android/settings/location/RecentLocationRequestPreferenceController.java
+++ b/src/com/android/settings/location/RecentLocationRequestPreferenceController.java
@@ -25,7 +25,7 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.applications.InstalledAppDetails;
-import com.android.settings.applications.AppInfoDashboardFragment;
+import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.core.FeatureFlags;
import com.android.settings.widget.AppPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
diff --git a/src/com/android/settings/search/DatabaseIndexingUtils.java b/src/com/android/settings/search/DatabaseIndexingUtils.java
index 207d09f..94ec650 100644
--- a/src/com/android/settings/search/DatabaseIndexingUtils.java
+++ b/src/com/android/settings/search/DatabaseIndexingUtils.java
@@ -43,7 +43,7 @@
private static final String TAG = "IndexingUtil";
- private static final String FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER =
+ public static final String FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER =
"SEARCH_INDEX_DATA_PROVIDER";
/**
diff --git a/src/com/android/settings/search/XmlParserUtils.java b/src/com/android/settings/search/XmlParserUtils.java
index b4ffc53..27c5cd3 100644
--- a/src/com/android/settings/search/XmlParserUtils.java
+++ b/src/com/android/settings/search/XmlParserUtils.java
@@ -71,6 +71,10 @@
return getData(context, attrs, R.styleable.Preference, R.styleable.Preference_keywords);
}
+ public static String getController(Context context, AttributeSet attrs) {
+ return getData(context, attrs, R.styleable.Preference, R.styleable.Preference_controller);
+ }
+
public static int getDataIcon(Context context, AttributeSet attrs) {
final TypedArray ta = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.Preference);
diff --git a/src/com/android/settings/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
similarity index 67%
rename from src/com/android/settings/SettingsSliceProvider.java
rename to src/com/android/settings/slices/SettingsSliceProvider.java
index 845dacd..22035d2 100644
--- a/src/com/android/settings/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -14,28 +14,31 @@
* limitations under the License
*/
-package com.android.settings;
+package com.android.settings.slices;
import android.app.PendingIntent;
-import android.app.slice.Slice;
-import android.app.slice.SliceProvider;
+
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.net.Uri;
-import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import com.android.settings.R;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceProvider;
+import androidx.app.slice.builders.ListBuilder;
+
public class SettingsSliceProvider extends SliceProvider {
public static final String SLICE_AUTHORITY = "com.android.settings.slices";
public static final String PATH_WIFI = "wifi";
public static final String ACTION_WIFI_CHANGED =
"com.android.settings.slice.action.WIFI_CHANGED";
- // TODO -- Associate slice URI with search result instead of separate hardcoded thing
- public static final String[] WIFI_SEARCH_TERMS = {"wi-fi", "wifi", "internet"};
+ // TODO -- Associate slice URI with search result instead of separate hardcoded thing
public static Uri getUri(String path) {
return new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
@@ -44,7 +47,7 @@
}
@Override
- public boolean onCreate() {
+ public boolean onCreateSliceProvider() {
return true;
}
@@ -53,15 +56,15 @@
String path = sliceUri.getPath();
switch (path) {
case "/" + PATH_WIFI:
- return createWifi(sliceUri);
-
+ return createWifiSlice(sliceUri);
}
throw new IllegalArgumentException("Unrecognized slice uri: " + sliceUri);
}
- private Slice createWifi(Uri uri) {
+
+ // TODO (b/70622039) remove this when the proper wifi slice is enabled.
+ private Slice createWifiSlice(Uri sliceUri) {
// Get wifi state
- String[] toggleHints;
WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
int wifiState = wifiManager.getWifiState();
boolean wifiEnabled = false;
@@ -74,7 +77,6 @@
case WifiManager.WIFI_STATE_ENABLED:
case WifiManager.WIFI_STATE_ENABLING:
state = wifiManager.getConnectionInfo().getSSID();
- WifiInfo.removeDoubleQuotes(state);
wifiEnabled = true;
break;
case WifiManager.WIFI_STATE_UNKNOWN:
@@ -82,28 +84,17 @@
state = ""; // just don't show anything?
break;
}
- if (wifiEnabled) {
- toggleHints = new String[] {Slice.HINT_TOGGLE, Slice.HINT_SELECTED};
- } else {
- toggleHints = new String[] {Slice.HINT_TOGGLE};
- }
- // Construct the slice
- Slice.Builder b = new Slice.Builder(uri);
- b.addSubSlice(new Slice.Builder(b)
- .addAction(getIntent("android.settings.WIFI_SETTINGS"),
- new Slice.Builder(b)
- .addText(getContext().getString(R.string.wifi_settings), null)
- .addText(state, null)
- .addIcon(Icon.createWithResource(getContext(),
- R.drawable.ic_settings_wireless), null, Slice.HINT_HIDDEN)
- .addHints(Slice.HINT_TITLE)
- .build())
- .addAction(getBroadcastIntent(ACTION_WIFI_CHANGED),
- new Slice.Builder(b)
- .addHints(toggleHints)
- .build())
- .build());
- return b.build();
+
+ boolean finalWifiEnabled = wifiEnabled;
+ return new ListBuilder(sliceUri)
+ .setColor(R.color.material_blue_500)
+ .add(b -> b
+ .setTitle(getContext().getString(R.string.wifi_settings))
+ .setTitleItem(Icon.createWithResource(getContext(), R.drawable.wifi_signal))
+ .setSubtitle(state)
+ .addToggle(getBroadcastIntent(ACTION_WIFI_CHANGED), finalWifiEnabled)
+ .setContentIntent(getIntent(Intent.ACTION_MAIN)))
+ .build();
}
private PendingIntent getIntent(String action) {
diff --git a/src/com/android/settings/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java
similarity index 85%
rename from src/com/android/settings/SliceBroadcastReceiver.java
rename to src/com/android/settings/slices/SliceBroadcastReceiver.java
index f43e3a3..b6f2ab9 100644
--- a/src/com/android/settings/SliceBroadcastReceiver.java
+++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java
@@ -14,9 +14,9 @@
* limitations under the License
*/
-package com.android.settings;
+package com.android.settings.slices;
-import static com.android.settings.SettingsSliceProvider.ACTION_WIFI_CHANGED;
+import static com.android.settings.slices.SettingsSliceProvider.ACTION_WIFI_CHANGED;
import android.app.slice.Slice;
import android.content.BroadcastReceiver;
@@ -42,8 +42,8 @@
// Wait a bit for wifi to update (TODO: is there a better way to do this?)
Handler h = new Handler();
h.postDelayed(() -> {
- Uri uri = SettingsSliceProvider.getUri(SettingsSliceProvider.PATH_WIFI);
- context.getContentResolver().notifyChange(uri, null);
+ Uri uri = SettingsSliceProvider.getUri(SettingsSliceProvider.PATH_WIFI);
+ context.getContentResolver().notifyChange(uri, null);
}, 1000);
break;
}
diff --git a/src/com/android/settings/slices/SliceData.java b/src/com/android/settings/slices/SliceData.java
new file mode 100644
index 0000000..528f23c
--- /dev/null
+++ b/src/com/android/settings/slices/SliceData.java
@@ -0,0 +1,188 @@
+/*
+ * 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
+ */
+
+package com.android.settings.slices;
+
+import android.net.Uri;
+import android.text.TextUtils;
+
+/**
+ * TODO (b/67996923) Add SlicesIndexingManager
+ * Data class representing a slice stored by {@link SlicesIndexingManager}.
+ * Note that {@link #key} is treated as a primary key for this class and determines equality.
+ */
+public class SliceData {
+
+ private final String key;
+
+ private final String title;
+
+ private final String summary;
+
+ private final String screenTitle;
+
+ private final int iconResource;
+
+ private final String fragmentClassName;
+
+ private final Uri uri;
+
+ private final String preferenceController;
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getSummary() {
+ return summary;
+ }
+
+ public String getScreenTitle() {
+ return screenTitle;
+ }
+
+ public int getIconResource() {
+ return iconResource;
+ }
+
+ public String getFragmentClassName() {
+ return fragmentClassName;
+ }
+
+ public Uri getUri() {
+ return uri;
+ }
+
+ public String getPreferenceController() {
+ return preferenceController;
+ }
+
+ private SliceData(Builder builder) {
+ key = builder.mKey;
+ title = builder.mTitle;
+ summary = builder.mSummary;
+ screenTitle = builder.mScreenTitle;
+ iconResource = builder.mIconResource;
+ fragmentClassName = builder.mFragmentClassName;
+ uri = builder.mUri;
+ preferenceController = builder.mPrefControllerClassName;
+ }
+
+ @Override
+ public int hashCode() {
+ return key.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof SliceData)) {
+ return false;
+ }
+ SliceData newObject = (SliceData) obj;
+ return TextUtils.equals(key, newObject.key);
+ }
+
+ static class Builder {
+ private String mKey;
+
+ private String mTitle;
+
+ private String mSummary;
+
+ private String mScreenTitle;
+
+ private int mIconResource;
+
+ private String mFragmentClassName;
+
+ private Uri mUri;
+
+ private String mPrefControllerClassName;
+
+ public Builder setKey(String key) {
+ mKey = key;
+ return this;
+ }
+
+ public Builder setTitle(String title) {
+ mTitle = title;
+ return this;
+ }
+
+ public Builder setSummary(String summary) {
+ mSummary = summary;
+ return this;
+ }
+
+ public Builder setScreenTitle(String screenTitle) {
+ mScreenTitle = screenTitle;
+ return this;
+ }
+
+ public Builder setIcon(int iconResource) {
+ mIconResource = iconResource;
+ return this;
+ }
+
+ public Builder setPreferenceControllerClassName(String controllerClassName) {
+ mPrefControllerClassName = controllerClassName;
+ return this;
+ }
+
+ public Builder setFragmentName(String fragmentClassName) {
+ mFragmentClassName = fragmentClassName;
+ return this;
+ }
+
+ public Builder setUri(Uri uri) {
+ mUri = uri;
+ return this;
+ }
+
+ public SliceData build() {
+ if (TextUtils.isEmpty(mKey)) {
+ throw new IllegalStateException("Key cannot be empty");
+ }
+
+ if (TextUtils.isEmpty(mTitle)) {
+ throw new IllegalStateException("Title cannot be empty");
+ }
+
+ if (TextUtils.isEmpty(mFragmentClassName)) {
+ throw new IllegalStateException("Fragment Name cannot be empty");
+ }
+
+ if (TextUtils.isEmpty(mPrefControllerClassName)) {
+ throw new IllegalStateException("Preference Controller cannot be empty");
+ }
+
+ if (mUri == null) {
+ throw new IllegalStateException("Uri cannot be null");
+ }
+
+ return new SliceData(this);
+ }
+
+ public String getKey() {
+ return mKey;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/com/android/settings/slices/SlicesDatabaseHelper.java b/src/com/android/settings/slices/SlicesDatabaseHelper.java
new file mode 100644
index 0000000..a74fc81
--- /dev/null
+++ b/src/com/android/settings/slices/SlicesDatabaseHelper.java
@@ -0,0 +1,122 @@
+package com.android.settings.slices;
+
+import android.content.Context;
+
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Defines the schema for the Slices database.
+ */
+public class SlicesDatabaseHelper extends SQLiteOpenHelper {
+
+ private static final String TAG = "SlicesDatabaseHelper";
+
+ private static final String DATABASE_NAME = "slices_index.db";
+ private static final String SHARED_PREFS_TAG = "slices_shared_prefs";
+
+ private static final int DATABASE_VERSION = 1;
+
+ public interface Tables {
+ String TABLE_SLICES_INDEX = "slices_index";
+ }
+
+ public interface IndexColumns {
+ /**
+ * Primary key of the DB. Preference key from preference controllers.
+ */
+ String KEY = "key";
+
+ /**
+ * Title of the Setting.
+ */
+ String TITLE = "title";
+
+ /**
+ * Summary / Subtitle for the setting.
+ */
+ String SUBTITLE = "subtitle";
+
+ /**
+ * Title of the Setting screen on which the Setting lives.
+ */
+ String SCREENTITLE = "screentitle";
+
+ /**
+ * Resource ID for the icon of the setting. Should be 0 for no icon.
+ */
+ String ICON_RESOURCE = "icon";
+
+ /**
+ * Classname of the fragment name of the page that hosts the setting.
+ */
+ String FRAGMENT = "fragment";
+
+ /**
+ * Class name of the controller backing the setting. Must be a
+ * {@link com.android.settings.core.BasePreferenceController}.
+ */
+ String CONTROLLER = "controller";
+ }
+
+ private static final String CREATE_SLICES_TABLE =
+ "CREATE VIRTUAL TABLE " + Tables.TABLE_SLICES_INDEX + " USING fts4" +
+ "(" +
+ IndexColumns.KEY +
+ ", " +
+ IndexColumns.TITLE +
+ ", " +
+ IndexColumns.SUBTITLE +
+ ", " +
+ IndexColumns.SCREENTITLE +
+ ", " +
+ IndexColumns.ICON_RESOURCE +
+ ", " +
+ IndexColumns.FRAGMENT +
+ ", " +
+ IndexColumns.CONTROLLER +
+ ");";
+
+ private final Context mContext;
+
+ public SlicesDatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null /* CursorFactor */, DATABASE_VERSION);
+ mContext = context;
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ createDatabases(db);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ if (oldVersion < DATABASE_VERSION) {
+ Log.d(TAG, "Reconstructing DB from " + oldVersion + "to " + newVersion);
+ reconstruct(db);
+ }
+ }
+
+ @VisibleForTesting
+ void reconstruct(SQLiteDatabase db) {
+ mContext.getSharedPreferences(SHARED_PREFS_TAG, Context.MODE_PRIVATE)
+ .edit()
+ .clear()
+ .commit();
+ dropTables(db);
+ createDatabases(db);
+ }
+
+ private void createDatabases(SQLiteDatabase db) {
+ db.execSQL(CREATE_SLICES_TABLE);
+ Log.d(TAG, "Created databases");
+ }
+
+
+ private void dropTables(SQLiteDatabase db) {
+ db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_SLICES_INDEX);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/system/SystemDashboardFragment.java b/src/com/android/settings/system/SystemDashboardFragment.java
index c01bfcc..323a2d4 100644
--- a/src/com/android/settings/system/SystemDashboardFragment.java
+++ b/src/com/android/settings/system/SystemDashboardFragment.java
@@ -16,8 +16,12 @@
package com.android.settings.system;
import android.content.Context;
+import android.os.Bundle;
import android.os.UserManager;
import android.provider.SearchIndexableResource;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceGroup;
+import android.support.v7.preference.PreferenceScreen;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
@@ -41,6 +45,17 @@
private static final String KEY_RESET = "reset_dashboard";
@Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ final PreferenceScreen screen = getPreferenceScreen();
+ // We do not want to display an advanced button if only one setting is hidden
+ if (getVisiblePreferenceCount(screen) == screen.getInitialExpandedChildrenCount() + 1) {
+ screen.setInitialExpandedChildrenCount(Integer.MAX_VALUE);
+ }
+ }
+
+ @Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.SETTINGS_SYSTEM_CATEGORY;
}
@@ -67,13 +82,26 @@
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
- controllers.add(new SystemUpdatePreferenceController(context, UserManager.get(context)));
+ controllers.add(new SystemUpdatePreferenceController(context));
controllers.add(new AdditionalSystemUpdatePreferenceController(context));
controllers.add(new BackupSettingsActivityPreferenceController(context));
controllers.add(new GesturesSettingPreferenceController(context));
return controllers;
}
+ private int getVisiblePreferenceCount(PreferenceGroup group) {
+ int visibleCount = 0;
+ for (int i = 0; i < group.getPreferenceCount(); i++) {
+ final Preference preference = group.getPreference(i);
+ if (preference instanceof PreferenceGroup) {
+ visibleCount += getVisiblePreferenceCount((PreferenceGroup) preference);
+ } else if (preference.isVisible()) {
+ visibleCount++;
+ }
+ }
+ return visibleCount;
+ }
+
/**
* For Search.
*/
@@ -88,17 +116,18 @@
}
@Override
- public List<AbstractPreferenceController> getPreferenceControllers(Context context) {
+ public List<AbstractPreferenceController> getPreferenceControllers(
+ Context context) {
return buildPreferenceControllers(context);
}
@Override
public List<String> getNonIndexableKeys(Context context) {
List<String> keys = super.getNonIndexableKeys(context);
- keys.add((new BackupSettingsActivityPreferenceController(context)
- .getPreferenceKey()));
+ keys.add((new BackupSettingsActivityPreferenceController(
+ context).getPreferenceKey()));
keys.add(KEY_RESET);
return keys;
}
};
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/widget/EntityHeaderController.java b/src/com/android/settings/widget/EntityHeaderController.java
index 5fa7586..0d07e67 100644
--- a/src/com/android/settings/widget/EntityHeaderController.java
+++ b/src/com/android/settings/widget/EntityHeaderController.java
@@ -45,7 +45,7 @@
import com.android.settings.applications.AppInfoBase;
import com.android.settings.applications.InstalledAppDetails;
import com.android.settings.applications.LayoutPreference;
-import com.android.settings.applications.AppInfoDashboardFragment;
+import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.core.FeatureFlags;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.applications.ApplicationsState;
diff --git a/tests/robotests/Android.mk b/tests/robotests/Android.mk
index 97e5e04..7271884 100644
--- a/tests/robotests/Android.mk
+++ b/tests/robotests/Android.mk
@@ -14,7 +14,7 @@
LOCAL_JAVA_LIBRARIES := \
junit \
- platform-robolectric-3.4.2-prebuilt \
+ platform-robolectric-3.5.1-prebuilt \
telephony-common
LOCAL_INSTRUMENTATION_FOR := Settings
@@ -42,4 +42,4 @@
LOCAL_ROBOTEST_TIMEOUT := 36000
-include prebuilts/misc/common/robolectric/3.4.2/run_robotests.mk
+include prebuilts/misc/common/robolectric/3.5.1/run_robotests.mk
diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider
index 6d3ec9a..ebcea43 100644
--- a/tests/robotests/assets/grandfather_not_implementing_index_provider
+++ b/tests/robotests/assets/grandfather_not_implementing_index_provider
@@ -1,4 +1,4 @@
-com.android.settings.applications.AppInfoDashboardFragment
+com.android.settings.applications.appinfo.AppInfoDashboardFragment
com.android.settings.bluetooth.DevicePickerFragment
com.android.settings.bluetooth.BluetoothDeviceDetailsFragment
com.android.settings.bluetooth.BluetoothPairingDetail
diff --git a/tests/robotests/assets/grandfather_not_implementing_indexable b/tests/robotests/assets/grandfather_not_implementing_indexable
index eee2add..a82c9ef 100644
--- a/tests/robotests/assets/grandfather_not_implementing_indexable
+++ b/tests/robotests/assets/grandfather_not_implementing_indexable
@@ -1,12 +1,10 @@
com.android.settings.accessibility.ToggleScreenMagnificationPreferenceFragment
-com.android.settings.deviceinfo.SimStatus
com.android.settings.deviceinfo.PrivateVolumeForget
com.android.settings.inputmethod.SpellCheckersSettings
com.android.settings.inputmethod.KeyboardLayoutPickerFragment
com.android.settings.fuelgauge.InactiveApps
com.android.settings.accessibility.CaptionPropertiesFragment
com.android.settings.accessibility.AccessibilitySettingsForSetupWizard
-com.android.settings.deviceinfo.ImeiInformation
com.android.settings.datausage.DataUsageList
com.android.settings.vpn2.AppManagementFragment
com.android.settings.vpn2.VpnSettings
diff --git a/tests/robotests/assets/grandfather_not_in_search_index_provider_registry b/tests/robotests/assets/grandfather_not_in_search_index_provider_registry
index 9fd41f2..666b224 100644
--- a/tests/robotests/assets/grandfather_not_in_search_index_provider_registry
+++ b/tests/robotests/assets/grandfather_not_in_search_index_provider_registry
@@ -1,3 +1,2 @@
com.android.settings.display.ScreenZoomPreferenceFragmentForSetupWizard
-com.android.settings.search.indexing.FakeSettingsFragment
-com.android.settings.deviceinfo.Status
+com.android.settings.search.indexing.FakeSettingsFragment
\ No newline at end of file
diff --git a/tests/robotests/res/xml-mcc999/about_legal.xml b/tests/robotests/res/xml-mcc999/about_legal.xml
index 53a2b89..3e008cb 100644
--- a/tests/robotests/res/xml-mcc999/about_legal.xml
+++ b/tests/robotests/res/xml-mcc999/about_legal.xml
@@ -30,5 +30,6 @@
<Preference
android:key="pref_key_1"
- android:title="bears_bears_bears"/>
+ android:title="bears_bears_bears"
+ settings:controller="mind_flayer"/>
</PreferenceScreen>
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/DeviceInfoSettingsTest.java b/tests/robotests/src/com/android/settings/DeviceInfoSettingsTest.java
index 486993d..09ff9db 100644
--- a/tests/robotests/src/com/android/settings/DeviceInfoSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/DeviceInfoSettingsTest.java
@@ -30,12 +30,9 @@
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
-import android.os.SystemProperties;
import android.support.v7.preference.PreferenceScreen;
import android.telephony.TelephonyManager;
-import android.util.FeatureFlagUtils;
-import com.android.settings.core.FeatureFlags;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -98,8 +95,6 @@
SettingsShadowSystemProperties.class
})
public void getPrefXml_shouldReturnDeviceInfoXml() {
- SystemProperties.set(FeatureFlagUtils.FFLAG_OVERRIDE_PREFIX + FeatureFlags.DEVICE_INFO_V2,
- "true");
assertThat(mSettings.getPreferenceScreenResId()).isEqualTo(R.xml.device_info_settings_v2);
}
@@ -142,8 +137,6 @@
@Config(shadows = {SettingsShadowResources.SettingsShadowTheme.class,
SettingsShadowSystemProperties.class})
public void onCreate_singleSim_shouldAddSingleSimCount() {
- SystemProperties.set(FeatureFlagUtils.FFLAG_OVERRIDE_PREFIX + FeatureFlags.DEVICE_INFO_V2,
- "true");
doReturn(1).when(mTelephonyManager).getPhoneCount();
mSettings.onCreate(null /* icicle */);
@@ -156,8 +149,6 @@
@Config(shadows = {SettingsShadowResources.SettingsShadowTheme.class,
SettingsShadowSystemProperties.class})
public void onCreate_dualeSim_shouldAddDualSimCount() {
- SystemProperties.set(FeatureFlagUtils.FFLAG_OVERRIDE_PREFIX + FeatureFlags.DEVICE_INFO_V2,
- "true");
doReturn(2).when(mTelephonyManager).getPhoneCount();
mSettings.onCreate(null /* icicle */);
diff --git a/tests/robotests/src/com/android/settings/HelpTrampolineTest.java b/tests/robotests/src/com/android/settings/HelpTrampolineTest.java
index e10b878..a6bcf03 100644
--- a/tests/robotests/src/com/android/settings/HelpTrampolineTest.java
+++ b/tests/robotests/src/com/android/settings/HelpTrampolineTest.java
@@ -50,7 +50,7 @@
final Intent intent = new Intent().setClassName(
RuntimeEnvironment.application.getPackageName(), HelpTrampoline.class.getName());
- Robolectric.buildActivity(HelpTrampoline.class).withIntent(intent).create().get();
+ Robolectric.buildActivity(HelpTrampoline.class, intent).create().get();
assertThat(ShadowHelpUtils.isGetHelpIntentCalled()).isFalse();
}
@@ -60,8 +60,8 @@
final Intent intent = new Intent().setClassName(
RuntimeEnvironment.application.getPackageName(), HelpTrampoline.class.getName())
.putExtra(Intent.EXTRA_TEXT, "help_url_upgrading");
- final ShadowActivity shadow = shadowOf(Robolectric.buildActivity(HelpTrampoline.class)
- .withIntent(intent).create().get());
+ final ShadowActivity shadow =
+ shadowOf(Robolectric.buildActivity(HelpTrampoline.class, intent).create().get());
final Intent launchedIntent = shadow.getNextStartedActivity();
assertThat(ShadowHelpUtils.isGetHelpIntentCalled()).isTrue();
diff --git a/tests/robotests/src/com/android/settings/applications/AppInfoDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/applications/AppInfoDashboardFragmentTest.java
deleted file mode 100644
index d710d7c..0000000
--- a/tests/robotests/src/com/android/settings/applications/AppInfoDashboardFragmentTest.java
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.settings.applications;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.AlertDialog;
-import android.app.AppOpsManager;
-import android.app.Fragment;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.os.UserManager;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceManager;
-import android.support.v7.preference.PreferenceScreen;
-import android.view.View;
-
-import com.android.settings.R;
-import com.android.settings.SettingsActivity;
-import com.android.settings.TestConfig;
-import com.android.settings.applications.instantapps.InstantAppButtonsController;
-import com.android.settings.applications.instantapps.InstantAppButtonsController.ShowDialogDelegate;
-import com.android.settings.testutils.FakeFeatureFactory;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.widget.ActionButtonPreferenceTest;
-import com.android.settings.wrapper.DevicePolicyManagerWrapper;
-import com.android.settingslib.Utils;
-import com.android.settingslib.applications.AppUtils;
-import com.android.settingslib.applications.ApplicationsState.AppEntry;
-import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.util.ReflectionHelpers;
-
-import java.util.HashSet;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-@Config(
- manifest = TestConfig.MANIFEST_PATH,
- sdk = TestConfig.SDK_VERSION
-)
-public final class AppInfoDashboardFragmentTest {
-
- private static final String PACKAGE_NAME = "test_package_name";
-
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private Context mContext;
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private UserManager mUserManager;
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private SettingsActivity mActivity;
- @Mock
- private DevicePolicyManagerWrapper mDevicePolicyManager;
- @Mock
- private PackageManager mPackageManager;
- @Mock
- private AppOpsManager mAppOpsManager;
-
- private FakeFeatureFactory mFeatureFactory;
- private AppInfoDashboardFragment mAppDetail;
- private Context mShadowContext;
-
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mFeatureFactory = FakeFeatureFactory.setupForTest();
- mShadowContext = RuntimeEnvironment.application;
- mAppDetail = spy(new AppInfoDashboardFragment());
- doReturn(mActivity).when(mAppDetail).getActivity();
- doReturn(mShadowContext).when(mAppDetail).getContext();
- doReturn(mPackageManager).when(mActivity).getPackageManager();
- doReturn(mAppOpsManager).when(mActivity).getSystemService(Context.APP_OPS_SERVICE);
- mAppDetail.mActionButtons = ActionButtonPreferenceTest.createMock();
-
- // Default to not considering any apps to be instant (individual tests can override this).
- ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
- (InstantAppDataProvider) (i -> false));
- }
-
- @Test
- public void shouldShowUninstallForAll_installForOneOtherUserOnly_shouldReturnTrue() {
- when(mDevicePolicyManager.packageHasActiveAdmins(nullable(String.class))).thenReturn(false);
- when(mUserManager.getUsers().size()).thenReturn(2);
- ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
- ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
- final ApplicationInfo info = new ApplicationInfo();
- info.enabled = true;
- final AppEntry appEntry = mock(AppEntry.class);
- appEntry.info = info;
- final PackageInfo packageInfo = mock(PackageInfo.class);
- ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
-
- assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isTrue();
- }
-
- @Test
- public void shouldShowUninstallForAll_installForSelfOnly_shouldReturnFalse() {
- when(mDevicePolicyManager.packageHasActiveAdmins(nullable(String.class))).thenReturn(false);
- when(mUserManager.getUsers().size()).thenReturn(2);
- ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
- ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
- final ApplicationInfo info = new ApplicationInfo();
- info.flags = ApplicationInfo.FLAG_INSTALLED;
- info.enabled = true;
- final AppEntry appEntry = mock(AppEntry.class);
- appEntry.info = info;
- final PackageInfo packageInfo = mock(PackageInfo.class);
- ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
-
- assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isFalse();
- }
-
- @Test
- public void launchFragment_hasNoPackageInfo_shouldFinish() {
- ReflectionHelpers.setField(mAppDetail, "mPackageInfo", null);
-
- assertThat(mAppDetail.ensurePackageInfoAvailable(mActivity)).isFalse();
- verify(mActivity).finishAndRemoveTask();
- }
-
- @Test
- public void launchFragment_hasPackageInfo_shouldReturnTrue() {
- final PackageInfo packageInfo = mock(PackageInfo.class);
- ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
-
- assertThat(mAppDetail.ensurePackageInfoAvailable(mActivity)).isTrue();
- verify(mActivity, never()).finishAndRemoveTask();
- }
-
- @Test
- public void packageSizeChange_isOtherPackage_shouldNotRefreshUi() {
- ReflectionHelpers.setField(mAppDetail, "mPackageName", PACKAGE_NAME);
- mAppDetail.onPackageSizeChanged("Not_" + PACKAGE_NAME);
-
- verify(mAppDetail, never()).refreshUi();
- }
-
- @Test
- public void packageSizeChange_isOwnPackage_shouldRefreshUi() {
- doReturn(Boolean.TRUE).when(mAppDetail).refreshUi();
- ReflectionHelpers.setField(mAppDetail, "mPackageName", PACKAGE_NAME);
-
- mAppDetail.onPackageSizeChanged(PACKAGE_NAME);
-
- verify(mAppDetail).refreshUi();
- }
-
- // Tests that we don't show the "uninstall for all users" button for instant apps.
- @Test
- public void instantApps_noUninstallForAllButton() {
- // Make this app appear to be instant.
- ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
- (InstantAppDataProvider) (i -> true));
- when(mDevicePolicyManager.packageHasActiveAdmins(nullable(String.class))).thenReturn(false);
- when(mUserManager.getUsers().size()).thenReturn(2);
-
- final ApplicationInfo info = new ApplicationInfo();
- info.enabled = true;
- final AppEntry appEntry = mock(AppEntry.class);
- appEntry.info = info;
- final PackageInfo packageInfo = mock(PackageInfo.class);
-
- ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
- ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
- ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
-
- assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isFalse();
- }
-
- // Tests that we don't show the uninstall button for instant apps"
- @Test
- public void instantApps_noUninstallButton() {
- // Make this app appear to be instant.
- ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
- (InstantAppDataProvider) (i -> true));
- final ApplicationInfo info = new ApplicationInfo();
- info.flags = ApplicationInfo.FLAG_INSTALLED;
- info.enabled = true;
- final AppEntry appEntry = mock(AppEntry.class);
- appEntry.info = info;
- final PackageInfo packageInfo = mock(PackageInfo.class);
- packageInfo.applicationInfo = info;
-
- ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
- ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
- ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
-
- mAppDetail.initUninstallButtonForUserApp();
- verify(mAppDetail.mActionButtons).setButton1Visible(false);
- }
-
- // Tests that we don't show the force stop button for instant apps (they aren't allowed to run
- // when they aren't in the foreground).
- @Test
- public void instantApps_noForceStop() {
- // Make this app appear to be instant.
- ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
- (InstantAppDataProvider) (i -> true));
- final PackageInfo packageInfo = mock(PackageInfo.class);
- final AppEntry appEntry = mock(AppEntry.class);
- final ApplicationInfo info = new ApplicationInfo();
- appEntry.info = info;
-
- ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
- ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
- ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
-
- mAppDetail.checkForceStop();
- verify(mAppDetail.mActionButtons).setButton2Visible(false);
- }
-
- @Test
- public void instantApps_buttonControllerHandlesDialog() {
- InstantAppButtonsController mockController = mock(InstantAppButtonsController.class);
- ReflectionHelpers.setField(
- mAppDetail, "mInstantAppButtonsController", mockController);
- // Make sure first that button controller is not called for supported dialog id
- AlertDialog mockDialog = mock(AlertDialog.class);
- when(mockController.createDialog(InstantAppButtonsController.DLG_CLEAR_APP))
- .thenReturn(mockDialog);
- assertThat(mAppDetail.createDialog(InstantAppButtonsController.DLG_CLEAR_APP, 0))
- .isEqualTo(mockDialog);
- verify(mockController).createDialog(InstantAppButtonsController.DLG_CLEAR_APP);
- }
-
- // A helper class for testing the InstantAppButtonsController - it lets us look up the
- // preference associated with a key for instant app buttons and get back a mock
- // LayoutPreference (to avoid a null pointer exception).
- public static class InstalledAppDetailsWithMockInstantButtons extends InstalledAppDetails {
- @Mock
- private LayoutPreference mInstantButtons;
-
- public InstalledAppDetailsWithMockInstantButtons() {
- super();
- MockitoAnnotations.initMocks(this);
- }
-
- @Override
- public Preference findPreference(CharSequence key) {
- if (key == "instant_app_buttons") {
- return mInstantButtons;
- }
- return super.findPreference(key);
- }
- }
-
- @Test
- public void instantApps_instantSpecificButtons() {
- // Make this app appear to be instant.
- ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
- (InstantAppDataProvider) (i -> true));
- final PackageInfo packageInfo = mock(PackageInfo.class);
-
- final InstalledAppDetailsWithMockInstantButtons
- fragment = new InstalledAppDetailsWithMockInstantButtons();
- ReflectionHelpers.setField(fragment, "mPackageInfo", packageInfo);
- ReflectionHelpers.setField(fragment, "mApplicationFeatureProvider",
- mFeatureFactory.applicationFeatureProvider);
-
- final InstantAppButtonsController buttonsController =
- mock(InstantAppButtonsController.class);
- when(buttonsController.setPackageName(nullable(String.class)))
- .thenReturn(buttonsController);
- when(mFeatureFactory.applicationFeatureProvider.newInstantAppButtonsController(
- nullable(Fragment.class), nullable(View.class), nullable(ShowDialogDelegate.class)))
- .thenReturn(buttonsController);
-
- fragment.maybeAddInstantAppButtons();
- verify(buttonsController).setPackageName(nullable(String.class));
- verify(buttonsController).show();
- }
-
- @Test
- public void instantApps_removeCorrectPref() {
- PreferenceScreen mockPreferenceScreen = mock(PreferenceScreen.class);
- PreferenceManager mockPreferenceManager = mock(PreferenceManager.class);
- AppDomainsPreference mockAppDomainsPref = mock(AppDomainsPreference.class);
- PackageInfo mockPackageInfo = mock(PackageInfo.class);
- PackageManager mockPackageManager = mock(PackageManager.class);
- ReflectionHelpers.setField(
- mAppDetail, "mInstantAppDomainsPreference", mockAppDomainsPref);
- ReflectionHelpers.setField(
- mAppDetail, "mPreferenceManager", mockPreferenceManager);
- ReflectionHelpers.setField(
- mAppDetail, "mPackageInfo", mockPackageInfo);
- ReflectionHelpers.setField(
- mAppDetail, "mPm", mockPackageManager);
- when(mockPreferenceManager.getPreferenceScreen()).thenReturn(mockPreferenceScreen);
-
- ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
- (InstantAppDataProvider) (i -> false));
- mAppDetail.prepareInstantAppPrefs();
-
- // For the non instant case we remove the app domain pref, and leave the launch pref
- verify(mockPreferenceScreen).removePreference(mockAppDomainsPref);
-
- // For the instant app case we remove the launch preff, and leave the app domain pref
- ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
- (InstantAppDataProvider) (i -> true));
-
- mAppDetail.prepareInstantAppPrefs();
- // Will be 1 still due to above call
- verify(mockPreferenceScreen, times(1))
- .removePreference(mockAppDomainsPref);
- }
-
- @Test
- public void onActivityResult_uninstalledUpdates_shouldInvalidateOptionsMenu() {
- doReturn(true).when(mAppDetail).refreshUi();
-
- mAppDetail.onActivityResult(InstalledAppDetails.REQUEST_UNINSTALL, 0, mock(Intent.class));
-
- verify(mActivity).invalidateOptionsMenu();
- }
-
- @Test
- public void handleDisableable_appIsHomeApp_buttonShouldNotWork() {
- final ApplicationInfo info = new ApplicationInfo();
- info.packageName = "pkg";
- info.enabled = true;
- final AppEntry appEntry = mock(AppEntry.class);
- appEntry.info = info;
- final HashSet<String> homePackages = new HashSet<>();
- homePackages.add(info.packageName);
-
- ReflectionHelpers.setField(mAppDetail, "mHomePackages", homePackages);
- ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
-
- assertThat(mAppDetail.handleDisableable()).isFalse();
- verify(mAppDetail.mActionButtons).setButton1Text(R.string.disable_text);
- }
-
- @Test
- @Config(shadows = ShadowUtils.class)
- public void handleDisableable_appIsEnabled_buttonShouldWork() {
- final ApplicationInfo info = new ApplicationInfo();
- info.packageName = "pkg";
- info.enabled = true;
- info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-
- final AppEntry appEntry = mock(AppEntry.class);
- appEntry.info = info;
- when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages()).thenReturn(
- new HashSet<>());
-
- ReflectionHelpers.setField(mAppDetail, "mApplicationFeatureProvider",
- mFeatureFactory.applicationFeatureProvider);
- ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
-
- assertThat(mAppDetail.handleDisableable()).isTrue();
- verify(mAppDetail.mActionButtons).setButton1Text(R.string.disable_text);
- }
-
- @Test
- @Config(shadows = ShadowUtils.class)
- public void handleDisableable_appIsDisabled_buttonShouldShowEnable() {
- final ApplicationInfo info = new ApplicationInfo();
- info.packageName = "pkg";
- info.enabled = false;
- info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-
- final AppEntry appEntry = mock(AppEntry.class);
- appEntry.info = info;
- when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages()).thenReturn(
- new HashSet<>());
-
- ReflectionHelpers.setField(mAppDetail, "mApplicationFeatureProvider",
- mFeatureFactory.applicationFeatureProvider);
- ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
-
- assertThat(mAppDetail.handleDisableable()).isTrue();
- verify(mAppDetail.mActionButtons).setButton1Text(R.string.enable_text);
- verify(mAppDetail.mActionButtons).setButton1Positive(true);
- }
-
- @Test
- @Config(shadows = ShadowUtils.class)
- public void handleDisableable_appIsEnabledAndInKeepEnabledWhitelist_buttonShouldNotWork() {
- final ApplicationInfo info = new ApplicationInfo();
- info.packageName = "pkg";
- info.enabled = true;
- info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-
- final AppEntry appEntry = mock(AppEntry.class);
- appEntry.info = info;
-
- final HashSet<String> packages = new HashSet<>();
- packages.add(info.packageName);
- when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages()).thenReturn(
- packages);
-
- ReflectionHelpers.setField(mAppDetail, "mApplicationFeatureProvider",
- mFeatureFactory.applicationFeatureProvider);
- ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
-
- assertThat(mAppDetail.handleDisableable()).isFalse();
- verify(mAppDetail.mActionButtons).setButton1Text(R.string.disable_text);
- }
-
- @Test
- public void initUninstallButtonForUserApp_shouldSetNegativeButton() {
- final ApplicationInfo info = new ApplicationInfo();
- info.flags = ApplicationInfo.FLAG_INSTALLED;
- info.enabled = true;
- final PackageInfo packageInfo = mock(PackageInfo.class);
- packageInfo.applicationInfo = info;
- ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
- ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
-
- mAppDetail.initUninstallButtonForUserApp();
-
- verify(mAppDetail.mActionButtons).setButton1Positive(false);
- }
-
- @Implements(Utils.class)
- public static class ShadowUtils {
- @Implementation
- public static boolean isSystemPackage(Resources resources, PackageManager pm,
- PackageInfo pkg) {
- return false;
- }
- }
-}
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceControllerTest.java
new file mode 100644
index 0000000..17b7a22
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceControllerTest.java
@@ -0,0 +1,320 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.widget.ActionButtonPreference;
+import com.android.settings.widget.ActionButtonPreferenceTest;
+import com.android.settings.wrapper.DevicePolicyManagerWrapper;
+import com.android.settingslib.Utils;
+import com.android.settingslib.applications.AppUtils;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class AppActionButtonPreferenceControllerTest {
+
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private DevicePolicyManagerWrapper mDevicePolicyManager;
+ @Mock
+ private AppInfoDashboardFragment mFragment;
+
+ private Context mContext;
+ private AppActionButtonPreferenceController mController;
+ private FakeFeatureFactory mFeatureFactory;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mFeatureFactory = FakeFeatureFactory.setupForTest();
+ mContext = spy(RuntimeEnvironment.application);
+ mController = spy(new AppActionButtonPreferenceController(mContext, mFragment, "Package1"));
+ mController.mActionButtons = ActionButtonPreferenceTest.createMock();
+ ReflectionHelpers.setField(mController, "mUserManager", mUserManager);
+ ReflectionHelpers.setField(mController, "mDpm", mDevicePolicyManager);
+ ReflectionHelpers.setField(mController, "mApplicationFeatureProvider",
+ mFeatureFactory.applicationFeatureProvider);
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ }
+
+ @Test
+ public void displayPreference_shouldInitializeForceStopButton() {
+ final PreferenceScreen screen = mock(PreferenceScreen.class);
+ final ActionButtonPreference preference = spy(new ActionButtonPreference(mContext));
+ when(screen.findPreference(mController.getPreferenceKey())).thenReturn(preference);
+
+ mController.displayPreference(screen);
+
+ verify(preference).setButton2Positive(false);
+ verify(preference).setButton2Text(R.string.force_stop);
+ verify(preference).setButton2Enabled(false);
+ }
+
+ @Test
+ public void refreshUi_shouldRefreshButton() {
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+ final ApplicationInfo info = new ApplicationInfo();
+ appEntry.info = info;
+ doNothing().when(mController).checkForceStop(appEntry, packageInfo);
+ doNothing().when(mController).initUninstallButtons(appEntry, packageInfo);
+ when(mFragment.getAppEntry()).thenReturn(appEntry);
+ when(mFragment.getPackageInfo()).thenReturn(packageInfo);
+
+ mController.refreshUi();
+
+ verify(mController).checkForceStop(appEntry, packageInfo);
+ verify(mController).initUninstallButtons(appEntry, packageInfo);
+ }
+
+ @Test
+ public void initUninstallButtonForUserApp_shouldSetNegativeButton() {
+ final ApplicationInfo info = new ApplicationInfo();
+ info.flags = ApplicationInfo.FLAG_INSTALLED;
+ info.enabled = true;
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ packageInfo.applicationInfo = info;
+ when(mFragment.getPackageInfo()).thenReturn(packageInfo);
+
+ assertThat(mController.initUninstallButtonForUserApp()).isTrue();
+ verify(mController.mActionButtons).setButton1Positive(false);
+ }
+
+ // Tests that we don't show the uninstall button for instant apps"
+ @Test
+ public void initUninstallButtonForUserApp_instantApps_noUninstallButton() {
+ // Make this app appear to be instant.
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> true));
+ final ApplicationInfo info = new ApplicationInfo();
+ info.flags = ApplicationInfo.FLAG_INSTALLED;
+ info.enabled = true;
+ final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+ appEntry.info = info;
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ packageInfo.applicationInfo = info;
+ when(mFragment.getPackageInfo()).thenReturn(packageInfo);
+
+ assertThat(mController.initUninstallButtonForUserApp()).isFalse();
+ verify(mController.mActionButtons).setButton1Visible(false);
+ }
+
+ @Test
+ public void initUninstallButtonForUserApp_notInstalledForCurrentUser_shouldDisableButton() {
+ final ApplicationInfo info = new ApplicationInfo();
+ info.enabled = true;
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ packageInfo.applicationInfo = info;
+ when(mFragment.getPackageInfo()).thenReturn(packageInfo);
+ final int userID1 = 1;
+ final int userID2 = 2;
+ final List<UserInfo> userInfos = new ArrayList<>();
+ userInfos.add(new UserInfo(userID1, "User1", UserInfo.FLAG_PRIMARY));
+ userInfos.add(new UserInfo(userID2, "User2", UserInfo.FLAG_GUEST));
+ when(mUserManager.getUsers(true)).thenReturn(userInfos);
+
+ assertThat(mController.initUninstallButtonForUserApp()).isFalse();
+ }
+
+ // Tests that we don't show the force stop button for instant apps (they aren't allowed to run
+ // when they aren't in the foreground).
+ @Test
+ public void checkForceStop_instantApps_shouldNotShowForceStop() {
+ // Make this app appear to be instant.
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> true));
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+ final ApplicationInfo info = new ApplicationInfo();
+ appEntry.info = info;
+
+ mController.checkForceStop(appEntry, packageInfo);
+
+ verify(mController.mActionButtons).setButton2Visible(false);
+ }
+
+ @Test
+ public void checkForceStop_hasActiveAdmin_shouldDisableForceStop() {
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> false));
+ final String packageName = "Package1";
+ final PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = packageName;
+ final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+ when(mDevicePolicyManager.packageHasActiveAdmins(packageName)).thenReturn(true);
+
+ mController.checkForceStop(appEntry, packageInfo);
+
+ verify(mController.mActionButtons).setButton2Enabled(false);
+ }
+
+ @Test
+ public void checkForceStop_appRunning_shouldEnableForceStop() {
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> false));
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+ final ApplicationInfo info = new ApplicationInfo();
+ appEntry.info = info;
+
+ mController.checkForceStop(appEntry, packageInfo);
+
+ verify(mController.mActionButtons).setButton2Enabled(true);
+ }
+
+ @Test
+ public void checkForceStop_appStopped_shouldQueryPackageRestart() {
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> false));
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+ final ApplicationInfo info = new ApplicationInfo();
+ appEntry.info = info;
+ info.flags = ApplicationInfo.FLAG_STOPPED;
+ info.packageName = "com.android.setting";
+
+ mController.checkForceStop(appEntry, packageInfo);
+
+ verify(mContext).sendOrderedBroadcastAsUser(argThat(intent-> intent != null
+ && intent.getAction().equals(Intent.ACTION_QUERY_PACKAGE_RESTART)),
+ any(UserHandle.class), nullable(String.class), any(BroadcastReceiver.class),
+ nullable(Handler.class), anyInt(), nullable(String.class), nullable(Bundle.class));
+ }
+
+ @Test
+ public void handleDisableable_appIsHomeApp_buttonShouldNotWork() {
+ final ApplicationInfo info = new ApplicationInfo();
+ info.packageName = "pkg";
+ info.enabled = true;
+ final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+ appEntry.info = info;
+ final HashSet<String> homePackages = new HashSet<>();
+ homePackages.add(info.packageName);
+ ReflectionHelpers.setField(mController, "mHomePackages", homePackages);
+
+ assertThat(mController.handleDisableable(appEntry, mock(PackageInfo.class))).isFalse();
+ verify(mController.mActionButtons).setButton1Text(R.string.disable_text);
+ }
+
+ @Test
+ @Config(shadows = ShadowUtils.class)
+ public void handleDisableable_appIsEnabled_buttonShouldWork() {
+ final ApplicationInfo info = new ApplicationInfo();
+ info.packageName = "pkg";
+ info.enabled = true;
+ info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+ final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+ appEntry.info = info;
+ when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages())
+ .thenReturn(new HashSet<>());
+
+ assertThat(mController.handleDisableable(appEntry, mock(PackageInfo.class))).isTrue();
+ verify(mController.mActionButtons).setButton1Text(R.string.disable_text);
+ }
+
+ @Test
+ @Config(shadows = ShadowUtils.class)
+ public void handleDisableable_appIsDisabled_buttonShouldShowEnable() {
+ final ApplicationInfo info = new ApplicationInfo();
+ info.packageName = "pkg";
+ info.enabled = false;
+ info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+ final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+ appEntry.info = info;
+ when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages())
+ .thenReturn(new HashSet<>());
+
+ assertThat(mController.handleDisableable(appEntry, mock(PackageInfo.class))).isTrue();
+ verify(mController.mActionButtons).setButton1Text(R.string.enable_text);
+ verify(mController.mActionButtons).setButton1Positive(true);
+ }
+
+ @Test
+ @Config(shadows = ShadowUtils.class)
+ public void handleDisableable_appIsEnabledAndInKeepEnabledWhitelist_buttonShouldNotWork() {
+ final ApplicationInfo info = new ApplicationInfo();
+ info.packageName = "pkg";
+ info.enabled = true;
+ info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+ final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+ appEntry.info = info;
+ final HashSet<String> packages = new HashSet<>();
+ packages.add(info.packageName);
+ when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages())
+ .thenReturn(packages);
+
+ assertThat(mController.handleDisableable(appEntry, mock(PackageInfo.class))).isFalse();
+ verify(mController.mActionButtons).setButton1Text(R.string.disable_text);
+ }
+
+ @Implements(Utils.class)
+ public static class ShadowUtils {
+ @Implementation
+ public static boolean isSystemPackage(Resources resources, PackageManager pm,
+ PackageInfo pkg) {
+ return false;
+ }
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
index 3516445..91833f5 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
@@ -40,7 +40,6 @@
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.SettingsActivity;
import com.android.settings.TestConfig;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerTest.java
index b02e01e..76160ee 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerTest.java
@@ -37,7 +37,6 @@
import android.support.v7.preference.Preference;
import com.android.settings.TestConfig;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.datausage.AppDataUsage;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java
new file mode 100644
index 0000000..87b82ad
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
+
+import com.android.settings.SettingsActivity;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.wrapper.DevicePolicyManagerWrapper;
+import com.android.settingslib.applications.AppUtils;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(
+ manifest = TestConfig.MANIFEST_PATH,
+ sdk = TestConfig.SDK_VERSION
+)
+public final class AppInfoDashboardFragmentTest {
+
+ private static final String PACKAGE_NAME = "test_package_name";
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private UserManager mUserManager;
+ @Mock
+ private SettingsActivity mActivity;
+ @Mock
+ private DevicePolicyManagerWrapper mDevicePolicyManager;
+ @Mock
+ private PackageManager mPackageManager;
+
+ private AppInfoDashboardFragment mFragment;
+ private Context mShadowContext;
+
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mShadowContext = RuntimeEnvironment.application;
+ mFragment = spy(new AppInfoDashboardFragment());
+ doReturn(mActivity).when(mFragment).getActivity();
+ doReturn(mShadowContext).when(mFragment).getContext();
+ doReturn(mPackageManager).when(mActivity).getPackageManager();
+
+ // Default to not considering any apps to be instant (individual tests can override this).
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> false));
+ }
+
+ @Test
+ public void shouldShowUninstallForAll_installForOneOtherUserOnly_shouldReturnTrue() {
+ when(mDevicePolicyManager.packageHasActiveAdmins(nullable(String.class))).thenReturn(false);
+ when(mUserManager.getUsers().size()).thenReturn(2);
+ ReflectionHelpers.setField(mFragment, "mDpm", mDevicePolicyManager);
+ ReflectionHelpers.setField(mFragment, "mUserManager", mUserManager);
+ final ApplicationInfo info = new ApplicationInfo();
+ info.enabled = true;
+ final AppEntry appEntry = mock(AppEntry.class);
+ appEntry.info = info;
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ ReflectionHelpers.setField(mFragment, "mPackageInfo", packageInfo);
+
+ assertThat(mFragment.shouldShowUninstallForAll(appEntry)).isTrue();
+ }
+
+ @Test
+ public void shouldShowUninstallForAll_installForSelfOnly_shouldReturnFalse() {
+ when(mDevicePolicyManager.packageHasActiveAdmins(nullable(String.class))).thenReturn(false);
+ when(mUserManager.getUsers().size()).thenReturn(2);
+ ReflectionHelpers.setField(mFragment, "mDpm", mDevicePolicyManager);
+ ReflectionHelpers.setField(mFragment, "mUserManager", mUserManager);
+ final ApplicationInfo info = new ApplicationInfo();
+ info.flags = ApplicationInfo.FLAG_INSTALLED;
+ info.enabled = true;
+ final AppEntry appEntry = mock(AppEntry.class);
+ appEntry.info = info;
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ ReflectionHelpers.setField(mFragment, "mPackageInfo", packageInfo);
+
+ assertThat(mFragment.shouldShowUninstallForAll(appEntry)).isFalse();
+ }
+
+ @Test
+ public void launchFragment_hasNoPackageInfo_shouldFinish() {
+ ReflectionHelpers.setField(mFragment, "mPackageInfo", null);
+
+ assertThat(mFragment.ensurePackageInfoAvailable(mActivity)).isFalse();
+ verify(mActivity).finishAndRemoveTask();
+ }
+
+ @Test
+ public void launchFragment_hasPackageInfo_shouldReturnTrue() {
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ ReflectionHelpers.setField(mFragment, "mPackageInfo", packageInfo);
+
+ assertThat(mFragment.ensurePackageInfoAvailable(mActivity)).isTrue();
+ verify(mActivity, never()).finishAndRemoveTask();
+ }
+
+ @Test
+ public void packageSizeChange_isOtherPackage_shouldNotRefreshUi() {
+ ReflectionHelpers.setField(mFragment, "mPackageName", PACKAGE_NAME);
+ mFragment.onPackageSizeChanged("Not_" + PACKAGE_NAME);
+
+ verify(mFragment, never()).refreshUi();
+ }
+
+ @Test
+ public void packageSizeChange_isOwnPackage_shouldRefreshUi() {
+ doReturn(Boolean.TRUE).when(mFragment).refreshUi();
+ ReflectionHelpers.setField(mFragment, "mPackageName", PACKAGE_NAME);
+
+ mFragment.onPackageSizeChanged(PACKAGE_NAME);
+
+ verify(mFragment).refreshUi();
+ }
+
+ // Tests that we don't show the "uninstall for all users" button for instant apps.
+ @Test
+ public void instantApps_noUninstallForAllButton() {
+ // Make this app appear to be instant.
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> true));
+ when(mDevicePolicyManager.packageHasActiveAdmins(nullable(String.class))).thenReturn(false);
+ when(mUserManager.getUsers().size()).thenReturn(2);
+
+ final ApplicationInfo info = new ApplicationInfo();
+ info.enabled = true;
+ final AppEntry appEntry = mock(AppEntry.class);
+ appEntry.info = info;
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+
+ ReflectionHelpers.setField(mFragment, "mDpm", mDevicePolicyManager);
+ ReflectionHelpers.setField(mFragment, "mUserManager", mUserManager);
+ ReflectionHelpers.setField(mFragment, "mPackageInfo", packageInfo);
+
+ assertThat(mFragment.shouldShowUninstallForAll(appEntry)).isFalse();
+ }
+
+ @Test
+ public void onActivityResult_uninstalledUpdates_shouldInvalidateOptionsMenu() {
+ doReturn(true).when(mFragment).refreshUi();
+
+ mFragment.onActivityResult(mFragment.REQUEST_UNINSTALL, 0, mock(Intent.class));
+
+ verify(mActivity).invalidateOptionsMenu();
+ }
+
+ @Test
+ public void getNumberOfUserWithPackageInstalled_twoUsersInstalled_shouldReturnTwo()
+ throws PackageManager.NameNotFoundException{
+ final String packageName = "Package1";
+ final int userID1 = 1;
+ final int userID2 = 2;
+ final List<UserInfo> userInfos = new ArrayList<>();
+ userInfos.add(new UserInfo(userID1, "User1", UserInfo.FLAG_PRIMARY));
+ userInfos.add(new UserInfo(userID2, "yue", UserInfo.FLAG_GUEST));
+ when(mUserManager.getUsers(true)).thenReturn(userInfos);
+ ReflectionHelpers.setField(mFragment, "mUserManager", mUserManager);
+ final ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.flags = ApplicationInfo.FLAG_INSTALLED;
+ when(mPackageManager.getApplicationInfoAsUser(
+ packageName, PackageManager.GET_META_DATA, userID1))
+ .thenReturn(appInfo);
+ when(mPackageManager.getApplicationInfoAsUser(
+ packageName, PackageManager.GET_META_DATA, userID2))
+ .thenReturn(appInfo);
+ ReflectionHelpers.setField(mFragment, "mPm", mPackageManager);
+
+ assertThat(mFragment.getNumberOfUserWithPackageInstalled(packageName)).isEqualTo(2);
+ }
+
+ @Test
+ public void getNumberOfUserWithPackageInstalled_oneUserInstalled_shouldReturnOne()
+ throws PackageManager.NameNotFoundException{
+ final String packageName = "Package1";
+ final int userID1 = 1;
+ final int userID2 = 2;
+ final List<UserInfo> userInfos = new ArrayList<>();
+ userInfos.add(new UserInfo(userID1, "User1", UserInfo.FLAG_PRIMARY));
+ userInfos.add(new UserInfo(userID2, "yue", UserInfo.FLAG_GUEST));
+ when(mUserManager.getUsers(true)).thenReturn(userInfos);
+ ReflectionHelpers.setField(mFragment, "mUserManager", mUserManager);
+ final ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.flags = ApplicationInfo.FLAG_INSTALLED;
+ when(mPackageManager.getApplicationInfoAsUser(
+ packageName, PackageManager.GET_META_DATA, userID1))
+ .thenReturn(appInfo);
+ when(mPackageManager.getApplicationInfoAsUser(
+ packageName, PackageManager.GET_META_DATA, userID2))
+ .thenThrow(new PackageManager.NameNotFoundException());
+ ReflectionHelpers.setField(mFragment, "mPm", mPackageManager);
+
+ assertThat(mFragment.getNumberOfUserWithPackageInstalled(packageName)).isEqualTo(1);
+
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java
index 25dcab3..51b6ddf 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java
@@ -32,7 +32,6 @@
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.TestConfig;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.notification.AppNotificationSettings;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.applications.ApplicationsState;
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInstallerInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInstallerInfoPreferenceControllerTest.java
new file mode 100644
index 0000000..d8d11bc
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInstallerInfoPreferenceControllerTest.java
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.UserManager;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class AppInstallerInfoPreferenceControllerTest {
+
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private ApplicationInfo mAppInfo;
+ @Mock
+ private AppInfoDashboardFragment mFragment;
+ @Mock
+ private Preference mPreference;
+
+ private Context mContext;
+ private AppInstallerInfoPreferenceController mController;
+
+ @Before
+ public void setUp() throws PackageManager.NameNotFoundException {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ final String installerPackage = "Installer1";
+ when(mPackageManager.getInstallerPackageName(anyString())).thenReturn(installerPackage);
+ when(mPackageManager.getApplicationInfo(eq(installerPackage), anyInt()))
+ .thenReturn(mAppInfo);
+ mController = new AppInstallerInfoPreferenceController(mContext, mFragment, "Package1");
+ }
+
+ @Test
+ public void getAvailabilityStatus_managedProfile_shouldReturnDisabled() {
+ when(mUserManager.isManagedProfile()).thenReturn(true);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.DISABLED_FOR_USER);
+ }
+
+ @Test
+ public void getAvailabilityStatus_noAppLabel_shouldReturnDisabled() {
+ when(mUserManager.isManagedProfile()).thenReturn(false);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.DISABLED_FOR_USER);
+ }
+
+ @Test
+ public void getAvailabilityStatus_hasAppLabel_shouldReturnAvailable() {
+ when(mUserManager.isManagedProfile()).thenReturn(false);
+ when(mAppInfo.loadLabel(mPackageManager)).thenReturn("Label1");
+ mController = new AppInstallerInfoPreferenceController(mContext, mFragment, "Package1");
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.AVAILABLE);
+ }
+
+ @Test
+ public void updateState_shouldSetSummary() {
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ packageInfo.applicationInfo = mAppInfo;
+ when(mFragment.getPackageInfo()).thenReturn(packageInfo);
+
+ mController.updateState(mPreference);
+
+ verify(mPreference).setSummary(any());
+ }
+
+ @Test
+ public void updateState_noAppStoreLink_shouldDisablePreference() {
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ packageInfo.applicationInfo = mAppInfo;
+ when(mFragment.getPackageInfo()).thenReturn(packageInfo);
+ when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(null);
+
+ mController.updateState(mPreference);
+
+ verify(mPreference).setEnabled(false);
+ }
+
+ @Test
+ public void updateState_hasAppStoreLink_shouldSetPreferenceIntent() {
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ packageInfo.applicationInfo = mAppInfo;
+ when(mFragment.getPackageInfo()).thenReturn(packageInfo);
+ final ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.packageName = "Pkg1";
+ resolveInfo.activityInfo.name = "Name1";
+ when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo);
+
+ mController.updateState(mPreference);
+
+ verify(mPreference, never()).setEnabled(false);
+ verify(mPreference).setIntent(any(Intent.class));
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppMemoryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppMemoryPreferenceControllerTest.java
index d74e301..47844c5 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppMemoryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppMemoryPreferenceControllerTest.java
@@ -34,7 +34,6 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.TestConfig;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.applications.ProcStatsData;
import com.android.settings.applications.ProcessStatsDetail;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java
index 482f33c..0b747a8 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java
@@ -30,7 +30,6 @@
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.TestConfig;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.notification.AppNotificationSettings;
import com.android.settings.notification.NotificationBackend;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppOpenByDefaultPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppOpenByDefaultPreferenceControllerTest.java
index b708232..c5003cc 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppOpenByDefaultPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppOpenByDefaultPreferenceControllerTest.java
@@ -32,7 +32,6 @@
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.TestConfig;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.applications.AppLaunchSettings;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.applications.AppUtils;
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppPermissionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppPermissionPreferenceControllerTest.java
index f9f8d98..f0b415c 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppPermissionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppPermissionPreferenceControllerTest.java
@@ -34,7 +34,6 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.TestConfig;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.applications.ApplicationsState;
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppStoragePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppStoragePreferenceControllerTest.java
index 729914a..c069517 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppStoragePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppStoragePreferenceControllerTest.java
@@ -32,7 +32,6 @@
import android.support.v7.preference.Preference;
import com.android.settings.TestConfig;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.applications.AppStorageSettings;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppVersionPreferenceControllerTest.java
index 7418489..d6ecf3e 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppVersionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppVersionPreferenceControllerTest.java
@@ -25,7 +25,6 @@
import android.support.v7.preference.Preference;
import com.android.settings.TestConfig;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java
index 358e50d..e44fdfb 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java
@@ -31,7 +31,6 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.TestConfig;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.applications.DefaultAppSettings;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/DrawOverlayDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/DrawOverlayDetailPreferenceControllerTest.java
index a7468b5..18a29e3 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/DrawOverlayDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/DrawOverlayDetailPreferenceControllerTest.java
@@ -32,7 +32,6 @@
import android.support.v7.preference.Preference;
import com.android.settings.TestConfig;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourceDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourceDetailPreferenceControllerTest.java
index d500be9..7e542f7 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourceDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourceDetailPreferenceControllerTest.java
@@ -28,7 +28,6 @@
import android.support.v7.preference.Preference;
import com.android.settings.TestConfig;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourcesDetailsTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourcesDetailsTest.java
new file mode 100644
index 0000000..ce38a56
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourcesDetailsTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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
+ */
+
+package com.android.settings.applications.appinfo;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.os.UserManager;
+
+import com.android.settings.TestConfig;
+import com.android.settings.applications.AppStateInstallAppsBridge;
+import com.android.settings.applications.AppStateInstallAppsBridge.InstallAppsState;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.RestrictedSwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class ExternalSourcesDetailsTest {
+
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private RestrictedSwitchPreference mSwitchPref;
+ @Mock
+ private PackageInfo mPackageInfo;
+
+ private ExternalSourcesDetails mFragment;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mFragment = new ExternalSourcesDetails();
+ ReflectionHelpers.setField(mFragment, "mUserManager", mUserManager);
+ ReflectionHelpers.setField(mFragment, "mSwitchPref", mSwitchPref);
+ }
+
+ @Test
+ public void refreshUi_noPackageInfo_shouldReturnFalseAndNoCrash() {
+ mFragment.refreshUi();
+
+ assertThat(mFragment.refreshUi()).isFalse();
+ // should not crash
+ }
+
+ @Test
+ public void refreshUi_noApplicationInfo_shouldReturnFalseAndNoCrash() {
+ ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo);
+
+ mFragment.refreshUi();
+
+ assertThat(mFragment.refreshUi()).isFalse();
+ // should not crash
+ }
+
+ @Test
+ public void refreshUi_hasApplicationInfo_shouldReturnTrue() {
+ ReflectionHelpers.setField(mFragment, "mPackageInfo", mPackageInfo);
+ mPackageInfo.applicationInfo = new ApplicationInfo();
+ final AppStateInstallAppsBridge appBridge = mock(AppStateInstallAppsBridge.class);
+ ReflectionHelpers.setField(mFragment, "mAppBridge", appBridge);
+ when(appBridge.createInstallAppsStateFor(nullable(String.class), anyInt()))
+ .thenReturn(mock(InstallAppsState.class));
+
+ mFragment.refreshUi();
+
+ assertThat(mFragment.refreshUi()).isTrue();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/InstantAppButtonsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/InstantAppButtonsPreferenceControllerTest.java
new file mode 100644
index 0000000..eb8a082
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/InstantAppButtonsPreferenceControllerTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.support.v7.preference.PreferenceScreen;
+import android.view.View;
+
+import com.android.settings.TestConfig;
+import com.android.settings.applications.LayoutPreference;
+import com.android.settings.applications.instantapps.InstantAppButtonsController;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.applications.AppUtils;
+import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class InstantAppButtonsPreferenceControllerTest {
+
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private ApplicationInfo mAppInfo;
+ @Mock
+ private AppInfoDashboardFragment mFragment;
+
+ private Context mContext;
+ private InstantAppButtonsPreferenceController mController;
+ private FakeFeatureFactory mFeatureFactory;
+
+ @Before
+ public void setUp() throws PackageManager.NameNotFoundException {
+ MockitoAnnotations.initMocks(this);
+ mFeatureFactory = FakeFeatureFactory.setupForTest();
+ mContext = spy(RuntimeEnvironment.application);
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ packageInfo.applicationInfo = mAppInfo;
+ when(mFragment.getPackageInfo()).thenReturn(packageInfo);
+ mController =
+ spy(new InstantAppButtonsPreferenceController(mContext, mFragment, "Package1"));
+ }
+
+ @Test
+ public void getAvailabilityStatus_notInstantApp_shouldReturnDisabled() {
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> false));
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.DISABLED_FOR_USER);
+ }
+
+ @Test
+ public void getAvailabilityStatus_isInstantApp_shouldReturnAvailable() {
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> true));
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.AVAILABLE);
+ }
+
+ @Test
+ public void displayPreference_shouldSetPreferenceTitle() {
+ final PreferenceScreen screen = mock(PreferenceScreen.class);
+ final LayoutPreference preference = mock(LayoutPreference.class);
+ when(screen.findPreference(mController.getPreferenceKey())).thenReturn(preference);
+ when(mController.getApplicationFeatureProvider())
+ .thenReturn(mFeatureFactory.applicationFeatureProvider);
+ final InstantAppButtonsController buttonsController =
+ mock(InstantAppButtonsController.class);
+ when(buttonsController.setPackageName(nullable(String.class)))
+ .thenReturn(buttonsController);
+ when(mFeatureFactory.applicationFeatureProvider.newInstantAppButtonsController(
+ nullable(Fragment.class), nullable(View.class),
+ nullable(InstantAppButtonsController.ShowDialogDelegate.class)))
+ .thenReturn(buttonsController);
+
+ mController.displayPreference(screen);
+
+ verify(buttonsController).setPackageName(nullable(String.class));
+ verify(buttonsController).show();
+ }
+
+ @Test
+ public void createDialog_shouldReturnDialogFromButtonController() {
+ final InstantAppButtonsController buttonsController =
+ mock(InstantAppButtonsController.class);
+ ReflectionHelpers.setField(
+ mController, "mInstantAppButtonsController", buttonsController);
+ final AlertDialog mockDialog = mock(AlertDialog.class);
+ when(buttonsController.createDialog(InstantAppButtonsController.DLG_CLEAR_APP))
+ .thenReturn(mockDialog);
+
+ assertThat(mController.createDialog(InstantAppButtonsController.DLG_CLEAR_APP))
+ .isEqualTo(mockDialog);
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/InstantAppDomainsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/InstantAppDomainsPreferenceControllerTest.java
new file mode 100644
index 0000000..bb0b42a
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/InstantAppDomainsPreferenceControllerTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IntentFilterVerificationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.util.ArraySet;
+
+import com.android.settings.TestConfig;
+import com.android.settings.applications.AppDomainsPreference;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.applications.AppUtils;
+import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class InstantAppDomainsPreferenceControllerTest {
+
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private ApplicationInfo mAppInfo;
+ @Mock
+ private AppInfoDashboardFragment mFragment;
+ @Mock
+ private AppDomainsPreference mPreference;
+
+ private Context mContext;
+ private InstantAppDomainsPreferenceController mController;
+
+ @Before
+ public void setUp() throws PackageManager.NameNotFoundException {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ final PackageInfo packageInfo = mock(PackageInfo.class);
+ packageInfo.applicationInfo = mAppInfo;
+ packageInfo.packageName = "Package1";
+ when(mFragment.getPackageInfo()).thenReturn(packageInfo);
+ mController = new InstantAppDomainsPreferenceController(mContext, mFragment);
+ }
+
+ @Test
+ public void getAvailabilityStatus_notInstantApp_shouldReturnDisabled() {
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> false));
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.DISABLED_FOR_USER);
+ }
+
+ @Test
+ public void getAvailabilityStatus_isInstantApp_shouldReturnAvailable() {
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (i -> true));
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.AVAILABLE);
+ }
+
+ @Test
+ public void updateState_shouldSetPreferenceTitle() {
+ final String[] domain = { "Domain1" };
+ final ArraySet<String> domains = new ArraySet<>();
+ domains.add(domain[0]);
+ final List<IntentFilterVerificationInfo> infoList = new ArrayList<>();
+ final IntentFilterVerificationInfo info =
+ new IntentFilterVerificationInfo("Package1", domains);
+ infoList.add(info);
+
+ when(mPackageManager.getIntentFilterVerifications("Package1")).thenReturn(infoList);
+
+ mController.updateState(mPreference);
+
+ verify(mPreference).setTitles(domain);
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/PictureInPictureDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/PictureInPictureDetailPreferenceControllerTest.java
index 7d81168..cf37b36 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/PictureInPictureDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/PictureInPictureDetailPreferenceControllerTest.java
@@ -29,7 +29,6 @@
import com.android.settings.R;
import com.android.settings.TestConfig;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/WriteSystemSettingsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/WriteSystemSettingsPreferenceControllerTest.java
index fabcbb2..08133f0 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/WriteSystemSettingsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/WriteSystemSettingsPreferenceControllerTest.java
@@ -32,7 +32,6 @@
import android.support.v7.preference.Preference;
import com.android.settings.TestConfig;
-import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java
index cde95cd..62a0d42 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java
@@ -47,6 +47,7 @@
public class BluetoothDeviceRenamePreferenceControllerTest {
private static final String DEVICE_NAME = "Nightshade";
+ private static final String PREF_KEY = "bt_rename_devices";
@Mock
private LocalBluetoothAdapter mLocalAdapter;
@@ -66,10 +67,10 @@
mContext = spy(RuntimeEnvironment.application);
mPreference = new Preference(mContext);
- mPreference.setKey(BluetoothDeviceRenamePreferenceController.PREF_KEY);
+ mPreference.setKey(PREF_KEY);
mController = new BluetoothDeviceRenamePreferenceController(
- mContext, mFragment, mLocalAdapter);
+ mContext, PREF_KEY, mFragment, mLocalAdapter);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceControllerTest.java
new file mode 100644
index 0000000..aa9d266
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSwitchPreferenceControllerTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.TestConfig;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class BluetoothSwitchPreferenceControllerTest {
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private LocalBluetoothManager mBluetoothManager;
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private SwitchPreference mPreference;
+ @Mock
+ private RestrictionUtils mRestrictionUtils;
+ @Mock
+ private LocalBluetoothAdapter mLocalBluetoothAdapter;
+
+ private Context mContext;
+ private BluetoothSwitchPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application.getApplicationContext());
+ FakeFeatureFactory.setupForTest();
+
+ mController = new BluetoothSwitchPreferenceController(
+ mContext, mBluetoothManager, mRestrictionUtils);
+ when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+ when(mPreference.getKey()).thenReturn(mController.getPreferenceKey());
+ }
+
+ @Test
+ public void testGetAvailabilityStatus_adapterNull_returnDisabled() {
+ mController.mBluetoothAdapter = null;
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.DISABLED_UNSUPPORTED);
+ }
+
+ @Test
+ public void testGetAvailabilityStatus_adapterExisted_returnAvailable() {
+ mController.mBluetoothAdapter = mLocalBluetoothAdapter;
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.AVAILABLE);
+ }
+
+ @Test
+ public void testOnStart_shouldRegisterPreferenceChangeListener() {
+ mController.displayPreference(mScreen);
+ mController.onStart();
+
+ verify(mPreference).setOnPreferenceChangeListener(
+ any(BluetoothSwitchPreferenceController.SwitchController.class));
+ }
+
+ @Test
+ public void testOnStop_shouldRegisterPreferenceChangeListener() {
+ mController.displayPreference(mScreen);
+ mController.onStart();
+
+ mController.onStop();
+
+ verify(mPreference).setOnPreferenceChangeListener(null);
+ }
+
+ @Test
+ public void testIsChecked_adapterNull_returnFalse() {
+ mController.mBluetoothAdapter = null;
+
+ assertThat(mController.isChecked()).isFalse();
+ }
+
+ @Test
+ public void testIsChecked_adapterExisted_returnFromAdapter() {
+ mController.mBluetoothAdapter = mLocalBluetoothAdapter;
+ doReturn(true).when(mLocalBluetoothAdapter).isEnabled();
+
+ assertThat(mController.isChecked()).isTrue();
+ }
+
+ @Test
+ public void testSetChecked_adapterExisted() {
+ mController.mBluetoothAdapter = mLocalBluetoothAdapter;
+
+ mController.setChecked(true);
+
+ verify(mLocalBluetoothAdapter).setBluetoothEnabled(true);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java
index f9efc0b..aa5eb67 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java
@@ -37,6 +37,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
@@ -45,13 +46,17 @@
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class ConnectedDeviceGroupControllerTest {
+ private static final String PREFERENCE_KEY_1 = "pref_key_1";
+
@Mock
private DashboardFragment mDashboardFragment;
@Mock
private ConnectedBluetoothDeviceUpdater mConnectedBluetoothDeviceUpdater;
@Mock
- private PreferenceScreen mPreferenceScreen;
+ private ConnectedUsbDeviceUpdater mConnectedUsbDeviceUpdater;
@Mock
+ private PreferenceScreen mPreferenceScreen;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private PreferenceManager mPreferenceManager;
private PreferenceGroup mPreferenceGroup;
@@ -66,30 +71,33 @@
mContext = RuntimeEnvironment.application;
mPreference = new Preference(mContext);
+ mPreference.setKey(PREFERENCE_KEY_1);
mLifecycle = new Lifecycle(() -> mLifecycle);
mPreferenceGroup = spy(new PreferenceScreen(mContext, null));
doReturn(mPreferenceManager).when(mPreferenceGroup).getPreferenceManager();
doReturn(mContext).when(mDashboardFragment).getContext();
mConnectedDeviceGroupController = new ConnectedDeviceGroupController(mDashboardFragment,
- mLifecycle, mConnectedBluetoothDeviceUpdater);
+ mLifecycle, mConnectedBluetoothDeviceUpdater, mConnectedUsbDeviceUpdater);
mConnectedDeviceGroupController.mPreferenceGroup = mPreferenceGroup;
}
@Test
- public void testOnDeviceAdded_firstAdd_becomeVisible() {
+ public void testOnDeviceAdded_firstAdd_becomeVisibleAndPreferenceAdded() {
mConnectedDeviceGroupController.onDeviceAdded(mPreference);
assertThat(mPreferenceGroup.isVisible()).isTrue();
+ assertThat(mPreferenceGroup.findPreference(PREFERENCE_KEY_1)).isEqualTo(mPreference);
}
@Test
- public void testOnDeviceRemoved_lastRemove_becomeInvisible() {
+ public void testOnDeviceRemoved_lastRemove_becomeInvisibleAndPreferenceRemoved() {
mPreferenceGroup.addPreference(mPreference);
mConnectedDeviceGroupController.onDeviceRemoved(mPreference);
assertThat(mPreferenceGroup.isVisible()).isFalse();
+ assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0);
}
@Test
@@ -117,9 +125,11 @@
// register the callback in onStart()
mLifecycle.handleLifecycleEvent(android.arch.lifecycle.Lifecycle.Event.ON_START);
verify(mConnectedBluetoothDeviceUpdater).registerCallback();
+ verify(mConnectedUsbDeviceUpdater).registerCallback();
// unregister the callback in onStop()
mLifecycle.handleLifecycleEvent(android.arch.lifecycle.Lifecycle.Event.ON_STOP);
verify(mConnectedBluetoothDeviceUpdater).unregisterCallback();
+ verify(mConnectedUsbDeviceUpdater).unregisterCallback();
}
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedUsbDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedUsbDeviceUpdaterTest.java
new file mode 100644
index 0000000..16cd3a7
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedUsbDeviceUpdaterTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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
+ */
+package com.android.settings.connecteddevice;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.deviceinfo.UsbBackend;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class ConnectedUsbDeviceUpdaterTest {
+ private Context mContext;
+ private ConnectedUsbDeviceUpdater mDeviceUpdater;
+
+ @Mock
+ private UsbConnectionBroadcastReceiver mUsbReceiver;
+ @Mock
+ private DevicePreferenceCallback mDevicePreferenceCallback;
+ @Mock
+ private UsbBackend mUsbBackend;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = RuntimeEnvironment.application;
+ mDeviceUpdater = new ConnectedUsbDeviceUpdater(mContext, mDevicePreferenceCallback,
+ mUsbBackend);
+ mDeviceUpdater.mUsbReceiver = mUsbReceiver;
+ }
+
+ @Test
+ public void testInitUsbPreference_preferenceInit() {
+ mDeviceUpdater.initUsbPreference(mContext);
+
+ assertThat(mDeviceUpdater.mUsbPreference.getTitle()).isEqualTo("USB");
+ assertThat(mDeviceUpdater.mUsbPreference.getIcon()).isEqualTo(mContext.getDrawable(
+ R.drawable.ic_usb));
+ assertThat(mDeviceUpdater.mUsbPreference.isSelectable()).isFalse();
+ }
+
+ @Test
+ public void testInitUsbPreference_usbConnected_preferenceAdded() {
+ doReturn(true).when(mUsbReceiver).isConnected();
+
+ mDeviceUpdater.initUsbPreference(mContext);
+
+ verify(mDevicePreferenceCallback).onDeviceAdded(mDeviceUpdater.mUsbPreference);
+ }
+
+ @Test
+ public void testInitUsbPreference_usbDisconnected_preferenceRemoved() {
+ doReturn(false).when(mUsbReceiver).isConnected();
+
+ mDeviceUpdater.initUsbPreference(mContext);
+
+ verify(mDevicePreferenceCallback).onDeviceRemoved(mDeviceUpdater.mUsbPreference);
+ }
+
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/UsbConnectionBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/connecteddevice/UsbConnectionBroadcastReceiverTest.java
new file mode 100644
index 0000000..06bd5b7
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/connecteddevice/UsbConnectionBroadcastReceiverTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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
+ */
+package com.android.settings.connecteddevice;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.usb.UsbManager;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class UsbConnectionBroadcastReceiverTest {
+ private Context mContext;
+ private UsbConnectionBroadcastReceiver mReceiver;
+ private ShadowApplication mShadowApplication;
+
+ @Mock
+ private UsbConnectionBroadcastReceiver.UsbConnectionListener mListener;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mShadowApplication = ShadowApplication.getInstance();
+ mContext = RuntimeEnvironment.application;
+ mReceiver = new UsbConnectionBroadcastReceiver(mContext, mListener);
+ }
+
+ @Test
+ public void testOnReceive_usbConnected_invokeCallback() {
+ final Intent intent = new Intent();
+ intent.putExtra(UsbManager.USB_CONNECTED, true);
+
+ mReceiver.onReceive(mContext, intent);
+
+ verify(mListener).onUsbConnectionChanged(true);
+ }
+
+ @Test
+ public void testOnReceive_usbDisconnected_invokeCallback() {
+ final Intent intent = new Intent();
+ intent.putExtra(UsbManager.USB_CONNECTED, false);
+
+ mReceiver.onReceive(mContext, intent);
+
+ verify(mListener).onUsbConnectionChanged(false);
+ }
+
+ @Test
+ public void testRegister_invokeMethodTwice_registerOnce() {
+ mReceiver.register();
+ mReceiver.register();
+
+ final List<BroadcastReceiver> receivers = mShadowApplication.getReceiversForIntent(
+ new Intent(UsbManager.ACTION_USB_STATE));
+ assertHasOneUsbConnectionBroadcastReceiver(receivers);
+ }
+
+ @Test
+ public void testUnregister_invokeMethodTwice_unregisterOnce() {
+ mReceiver.register();
+ mReceiver.unregister();
+ mReceiver.unregister();
+
+ final List<BroadcastReceiver> receivers = mShadowApplication.getReceiversForIntent(
+ new Intent(UsbManager.ACTION_USB_STATE));
+ assertHasNoUsbConnectionBroadcastReceiver(receivers);
+ }
+
+ private void assertHasOneUsbConnectionBroadcastReceiver(List<BroadcastReceiver> receivers) {
+ boolean hasReceiver = false;
+ for (final BroadcastReceiver receiver : receivers) {
+ if (receiver instanceof UsbConnectionBroadcastReceiver) {
+ // If hasReceiver is true, then we're at the second copy of it so fail.
+ assertWithMessage(
+ "Only one instance of UsbConnectionBroadcastReceiver should be "
+ + "registered").that(
+ hasReceiver).isFalse();
+ hasReceiver = true;
+ }
+ }
+ assertThat(hasReceiver).isTrue();
+ }
+
+ private void assertHasNoUsbConnectionBroadcastReceiver(List<BroadcastReceiver> receivers) {
+ for (final BroadcastReceiver receiver : receivers) {
+ assertThat(receiver instanceof UsbConnectionBroadcastReceiver).isFalse();
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/core/BasePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/core/BasePreferenceControllerTest.java
index 54b58d1..da2197c 100644
--- a/tests/robotests/src/com/android/settings/core/BasePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/core/BasePreferenceControllerTest.java
@@ -117,4 +117,4 @@
assertThat(mPreferenceController.isSupported()).isTrue();
}
-}
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java b/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java
new file mode 100644
index 0000000..ed4e815
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java
@@ -0,0 +1,275 @@
+package com.android.settings.core;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.content.Context;
+import android.content.res.XmlResourceParser;
+import android.provider.SearchIndexableResource;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Xml;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.search.DatabaseIndexingUtils;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.SearchIndexableResources;
+import com.android.settings.search.XmlParserUtils;
+import com.android.settings.security.SecuritySettings;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class XmlControllerAttributeTest {
+
+ // List of classes that are too hard to mock in order to retrieve xml information.
+ private final List<Class> illegalClasses = new ArrayList<>(
+ Arrays.asList(
+ SecuritySettings.class
+ ));
+
+ // List of XML that could be retrieved from the illegalClasses list.
+ private final List<Integer> whitelistXml = new ArrayList<>(
+ Arrays.asList(
+ R.xml.security_settings_misc,
+ R.xml.security_settings_lockscreen_profile,
+ R.xml.security_settings_lockscreen,
+ R.xml.security_settings_chooser,
+ R.xml.security_settings_pattern_profile,
+ R.xml.security_settings_pin_profile,
+ R.xml.security_settings_password_profile,
+ R.xml.security_settings_pattern,
+ R.xml.security_settings_pin,
+ R.xml.security_settings_password,
+ R.xml.security_settings,
+ R.xml.security_settings_status
+ ));
+
+ private static final String NO_VALID_CONSTRUCTOR_ERROR =
+ "Controllers added in XML need a constructor following either:"
+ + "\n\tClassName(Context)\n\tClassName(Context, String)"
+ + "\nThese controllers are missing a valid constructor:\n";
+
+ private static final String NOT_BASE_PREF_CONTROLLER_ERROR =
+ "Controllers added in XML need to extend com.android.settings.core"
+ + ".BasePreferenceController\nThese controllers do not:\n";
+
+ private static final String BAD_CLASSNAME_ERROR =
+ "The following controllers set in the XML did not have valid class names:\n";
+
+ private static final String BAD_CONSTRUCTOR_ERROR =
+ "The constructor provided by the following classes were insufficient to instantiate "
+ + "the object. It could be due to being an interface, abstract, or an "
+ + "IllegalAccessException. Please fix the following classes:\n";
+
+ Context mContext;
+
+ private Set<Class> mProviderClassesCopy;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mProviderClassesCopy = new HashSet<>(SearchIndexableResources.providerValues());
+ }
+
+ @After
+ public void cleanUp() {
+ SearchIndexableResources.providerValues().clear();
+ SearchIndexableResources.providerValues().addAll(mProviderClassesCopy);
+ }
+
+ @Test
+ public void testAllIndexableXML_onlyValidBasePreferenceControllersAdded() {
+ Set<Integer> xmlSet = getIndexableXml();
+ xmlSet.addAll(whitelistXml);
+
+ List<String> xmlControllers = new ArrayList<>();
+ Set<String> invalidConstructors = new HashSet<>();
+ Set<String> invalidClassHierarchy = new HashSet<>();
+ Set<String> badClassNameControllers = new HashSet<>();
+ Set<String> badConstructorControllers = new HashSet<>();
+
+ for (int resId : xmlSet) {
+ xmlControllers.addAll(getXmlControllers(resId));
+ }
+
+ for (String controllerClassName : xmlControllers) {
+ Class<?> clazz = getClassFromClassName(controllerClassName);
+
+ if (clazz == null) {
+ badClassNameControllers.add(controllerClassName);
+ continue;
+ }
+
+ Constructor<?> constructor = getConstructorFromClass(clazz);
+
+ if (constructor == null) {
+ invalidConstructors.add(controllerClassName);
+ continue;
+ }
+
+ Object controller = getObjectFromConstructor(constructor);
+ if (controller == null) {
+ badConstructorControllers.add(controllerClassName);
+ continue;
+ }
+
+ if (!(controller instanceof BasePreferenceController)) {
+ invalidClassHierarchy.add(controllerClassName);
+ }
+ }
+
+ final String invalidConstructorError = buildErrorMessage(NO_VALID_CONSTRUCTOR_ERROR,
+ invalidConstructors);
+ final String invalidClassHierarchyError = buildErrorMessage(NOT_BASE_PREF_CONTROLLER_ERROR,
+ invalidClassHierarchy);
+ final String badClassNameError = buildErrorMessage(BAD_CLASSNAME_ERROR,
+ badClassNameControllers);
+ final String badConstructorError = buildErrorMessage(BAD_CONSTRUCTOR_ERROR,
+ badConstructorControllers);
+
+ assertWithMessage(invalidConstructorError).that(invalidConstructors).isEmpty();
+ assertWithMessage(invalidClassHierarchyError).that(invalidClassHierarchy).isEmpty();
+ assertWithMessage(badClassNameError).that(badClassNameControllers).isEmpty();
+ assertWithMessage(badConstructorError).that(badConstructorControllers).isEmpty();
+ }
+
+ private Set<Integer> getIndexableXml() {
+ Set<Integer> xmlResSet = new HashSet();
+
+ Collection<Class> indexableClasses = SearchIndexableResources.providerValues();
+ indexableClasses.removeAll(illegalClasses);
+
+ for (Class clazz : indexableClasses) {
+
+ Indexable.SearchIndexProvider provider = DatabaseIndexingUtils.getSearchIndexProvider(
+ clazz);
+
+ if (provider == null) {
+ continue;
+ }
+
+ List<SearchIndexableResource> resources = provider.getXmlResourcesToIndex(mContext,
+ true);
+
+ if (resources == null) {
+ continue;
+ }
+
+ for (SearchIndexableResource resource : resources) {
+ // Add '0's anyway. It won't break the test.
+ xmlResSet.add(resource.xmlResId);
+ }
+ }
+ return xmlResSet;
+ }
+
+ private List<String> getXmlControllers(int xmlResId) {
+ List<String> xmlControllers = new ArrayList<>();
+
+ XmlResourceParser parser;
+ try {
+ parser = mContext.getResources().getXml(xmlResId);
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ // Parse next until start tag is found
+ }
+
+ final int outerDepth = parser.getDepth();
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+ String controllerClassName;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ controllerClassName = XmlParserUtils.getController(mContext, attrs);
+ // If controller is not indexed, then it is not compatible with
+ if (!TextUtils.isEmpty(controllerClassName)) {
+ xmlControllers.add(controllerClassName);
+ }
+ }
+ } catch (Exception e) {
+ // Assume an issue with robolectric resources
+ }
+ return xmlControllers;
+ }
+
+ private String buildErrorMessage(String errorSummary, Set<String> errorClasses) {
+ final StringBuilder error = new StringBuilder(errorSummary);
+ for (String c : errorClasses) {
+ error.append(c).append("\n");
+ }
+ return error.toString();
+ }
+
+ private Class<?> getClassFromClassName(String className) {
+ Class<?> clazz = null;
+ try {
+ clazz = Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ }
+ return clazz;
+ }
+
+ private Constructor<?> getConstructorFromClass(Class<?> clazz) {
+ Constructor<?> constructor = null;
+ try {
+ constructor = clazz.getConstructor(Context.class);
+ } catch (NoSuchMethodException e) {
+ }
+
+ if (constructor != null) {
+ return constructor;
+ }
+
+ try {
+ constructor = clazz.getConstructor(Context.class, String.class);
+ } catch (NoSuchMethodException e) {
+ }
+
+ return constructor;
+ }
+
+ private Object getObjectFromConstructor(Constructor<?> constructor) {
+ Object controller = null;
+
+ try {
+ controller = constructor.newInstance(mContext);
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
+ IllegalArgumentException e) {
+ }
+
+ if (controller != null) {
+ return controller;
+ }
+
+ try {
+ controller = constructor.newInstance(mContext, "key");
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
+ IllegalArgumentException e) {
+ }
+
+ return controller;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/development/EnableGnssRawMeasFullTrackingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/EnableGnssRawMeasFullTrackingPreferenceControllerTest.java
new file mode 100644
index 0000000..95fd111
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/EnableGnssRawMeasFullTrackingPreferenceControllerTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.development;
+
+
+import static com.android.settings.development.EnableGnssRawMeasFullTrackingPreferenceController
+ .SETTING_VALUE_OFF;
+import static com.android.settings.development.EnableGnssRawMeasFullTrackingPreferenceController
+ .SETTING_VALUE_ON;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class EnableGnssRawMeasFullTrackingPreferenceControllerTest {
+
+ @Mock
+ private SwitchPreference mPreference;
+ @Mock
+ private PreferenceScreen mPreferenceScreen;
+
+ private Context mContext;
+ private EnableGnssRawMeasFullTrackingPreferenceController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mController = new EnableGnssRawMeasFullTrackingPreferenceController(mContext);
+ when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
+ mPreference);
+ mController.displayPreference(mPreferenceScreen);
+ }
+
+ @Test
+ public void onPreferenceChange_settingEnabled_enableGnssRawMeasFullTrackingShouldBeOn() {
+ mController.onPreferenceChange(mPreference, true /* new value */);
+
+ final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, -1 /* default */);
+
+ assertThat(mode).isEqualTo(SETTING_VALUE_ON);
+ }
+
+ @Test
+ public void onPreferenceChange_settingDisabled_enableGnssRawMeasFullTrackingShouldBeOff() {
+ mController.onPreferenceChange(mPreference, false /* new value */);
+
+ final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, -1 /* default */);
+
+ assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
+ }
+
+ @Test
+ public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, SETTING_VALUE_OFF);
+ mController.updateState(mPreference);
+
+ verify(mPreference).setChecked(false);
+ }
+
+ @Test
+ public void updateState_settingEnabled_preferenceShouldBeChecked() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, SETTING_VALUE_ON);
+ mController.updateState(mPreference);
+
+ verify(mPreference).setChecked(true);
+ }
+
+ @Test
+ public void onDeveloperOptionsSwitchDisabled_shouldDisablePreference() {
+ mController.onDeveloperOptionsSwitchDisabled();
+
+ final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, -1 /* default */);
+
+ assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
+ verify(mPreference).setChecked(false);
+ verify(mPreference).setEnabled(false);
+ }
+
+ @Test
+ public void onDeveloperOptionsSwitchEnabled_shouldEnablePreference() {
+ mController.onDeveloperOptionsSwitchEnabled();
+
+ verify(mPreference).setEnabled(true);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/BasebandVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/BasebandVersionPreferenceControllerTest.java
deleted file mode 100644
index f71bae6..0000000
--- a/tests/robotests/src/com/android/settings/deviceinfo/BasebandVersionPreferenceControllerTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.
- */
-package com.android.settings.deviceinfo;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.verify;
-import static org.robolectric.shadow.api.Shadow.extract;
-
-import android.net.ConnectivityManager;
-import android.support.v7.preference.Preference;
-
-import com.android.settings.TestConfig;
-import com.android.settings.deviceinfo.firmwareversion.BasebandVersionDialogController;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.testutils.shadow.SettingsShadowSystemProperties;
-import com.android.settings.testutils.shadow.ShadowConnectivityManager;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-/**
- * Deprecated in favor of {@link BasebandVersionDialogController}
- */
-@Deprecated
-@RunWith(SettingsRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
- shadows = ShadowConnectivityManager.class)
-public class BasebandVersionPreferenceControllerTest {
-
-
- @Mock
- private Preference mPreference;
-
- private BasebandVersionPreferenceController mController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mController = new BasebandVersionPreferenceController(RuntimeEnvironment.application);
- }
-
- @Test
- public void isAvailable_wifiOnly_shouldReturnFalse() {
- ShadowConnectivityManager connectivityManager =
- extract(RuntimeEnvironment.application.getSystemService(ConnectivityManager.class));
- connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false);
- assertThat(mController.isAvailable()).isFalse();
- }
-
- @Test
- public void isAvailable_hasMobile_shouldReturnTrue() {
- ShadowConnectivityManager connectivityManager =
- extract(RuntimeEnvironment.application.getSystemService(ConnectivityManager.class));
- connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, true);
- assertThat(mController.isAvailable()).isTrue();
- }
-
- @Config(shadows = {SettingsShadowSystemProperties.class})
- @Test
- public void updateState_shouldLoadFromSysProperty() {
- SettingsShadowSystemProperties.set("gsm.version.baseband", "test");
-
- mController.updateState(mPreference);
-
- verify(mPreference).setSummary("test");
- }
-}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/BatteryInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/BatteryInfoPreferenceControllerTest.java
deleted file mode 100644
index 0ccc139..0000000
--- a/tests/robotests/src/com/android/settings/deviceinfo/BatteryInfoPreferenceControllerTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.settings.deviceinfo;
-
-import static android.arch.lifecycle.Lifecycle.Event.ON_START;
-import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
-
-import static com.android.settings.deviceinfo.BatteryInfoPreferenceController
- .BATTERY_INFO_RECEIVER_INTENT_FILTER;
-import static com.android.settings.deviceinfo.BatteryInfoPreferenceController.KEY_BATTERY_LEVEL;
-import static com.android.settings.deviceinfo.BatteryInfoPreferenceController.KEY_BATTERY_STATUS;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.BatteryManager;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settings.TestConfig;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class BatteryInfoPreferenceControllerTest {
-
- private Context mContext;
- @Mock
- private PreferenceScreen mScreen;
-
- private Preference mBatteryLevel;
- private Preference mBatteryStatus;
- private Lifecycle mLifecycle;
- private BatteryInfoPreferenceController mController;
-
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
- mLifecycle = new Lifecycle(() -> mLifecycle);
- mController = new BatteryInfoPreferenceController(mContext, mLifecycle);
- mBatteryLevel = new Preference(mContext);
- mBatteryStatus = new Preference(mContext);
- when(mScreen.findPreference(KEY_BATTERY_STATUS)).thenReturn(mBatteryStatus);
- when(mScreen.findPreference(KEY_BATTERY_LEVEL)).thenReturn(mBatteryLevel);
- }
-
- @Test
- public void isAlwaysAvailable() {
- assertThat(mController.getPreferenceKey()).isNull();
- assertThat(mController.isAvailable()).isTrue();
- }
-
- @Test
- public void runThroughLifecycle_shouldRegisterUnregisterBatteryInfoReceiver() {
- final Context context = mock(Context.class);
- mController = new BatteryInfoPreferenceController(context, mLifecycle);
- mLifecycle.handleLifecycleEvent(ON_START);
- mLifecycle.handleLifecycleEvent(ON_STOP);
-
- verify(context).registerReceiver(mController.mBatteryInfoReceiver,
- BATTERY_INFO_RECEIVER_INTENT_FILTER);
- verify(context).unregisterReceiver(mController.mBatteryInfoReceiver);
- }
-
- @Test
- public void onReceiveBatteryInfoBroadcast_shouldUpdatePreferences() {
- mController.displayPreference(mScreen);
- final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
- intent.putExtra(BatteryManager.EXTRA_LEVEL, 50);
- intent.putExtra(BatteryManager.EXTRA_SCALE, 100);
- intent.putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_CHARGING);
-
- mController.mBatteryInfoReceiver.onReceive(mContext, intent);
-
- assertThat(mBatteryLevel.getSummary()).isEqualTo("50%");
- assertThat(mBatteryStatus.getSummary())
- .isEqualTo(mContext.getText(R.string.battery_info_status_charging));
- }
-}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/DeviceModelPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/DeviceModelPreferenceControllerTest.java
index 347ca3a..6a5c7fa 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/DeviceModelPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/DeviceModelPreferenceControllerTest.java
@@ -19,6 +19,7 @@
import static com.android.settings.deviceinfo.DeviceModelPreferenceController.getDeviceModel;
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
@@ -26,16 +27,12 @@
import android.app.Fragment;
import android.content.Context;
-import android.os.SystemProperties;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
-import android.util.FeatureFlagUtils;
import com.android.settings.R;
import com.android.settings.TestConfig;
-import com.android.settings.core.FeatureFlags;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.testutils.shadow.SettingsShadowSystemProperties;
import org.junit.Before;
import org.junit.Test;
@@ -57,6 +54,7 @@
@Mock
private PreferenceScreen mPreferenceScreen;
+
private Context mContext;
private DeviceModelPreferenceController mController;
@@ -76,12 +74,7 @@
}
@Test
- @Config(shadows = {
- SettingsShadowSystemProperties.class
- })
public void displayPref_shouldSetSummary() {
- SystemProperties.set(FeatureFlagUtils.FFLAG_OVERRIDE_PREFIX + FeatureFlags.DEVICE_INFO_V2,
- "true");
mController.displayPreference(mPreferenceScreen);
verify(mPreference).setSummary(mContext.getResources().getString(R.string.model_summary,
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/FirmwareVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/FirmwareVersionPreferenceControllerTest.java
deleted file mode 100644
index 09b2e7f..0000000
--- a/tests/robotests/src/com/android/settings/deviceinfo/FirmwareVersionPreferenceControllerTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.
- */
-package com.android.settings.deviceinfo;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.UserManager;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
-
-import com.android.settings.TestConfig;
-import com.android.settings.deviceinfo.firmwareversion.FirmwareVersionDialogController;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
-
-/**
- * Deprecated in favor of {@link FirmwareVersionDialogController}
- */
-@Deprecated
-@RunWith(SettingsRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class FirmwareVersionPreferenceControllerTest {
-
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private Context mContext;
- @Mock
- private Preference mPreference;
- @Mock
- private PreferenceScreen mPreferenceScreen;
- @Mock
- private UserManager mUserManager;
- private FirmwareVersionPreferenceController mController;
- private Lifecycle mLifecycle;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mLifecycle = new Lifecycle(() -> mLifecycle);
- when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
- when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(null);
- mController = new FirmwareVersionPreferenceController(mContext, mLifecycle);
- when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
- .thenReturn(mPreference);
- }
-
- @Test
- public void isAlwaysAvailable() {
- assertThat(mController.isAvailable()).isTrue();
- }
-}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/SystemUpdatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/SystemUpdatePreferenceControllerTest.java
index 05670e2..1fd5430 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/SystemUpdatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/SystemUpdatePreferenceControllerTest.java
@@ -57,7 +57,9 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mController = new SystemUpdatePreferenceController(mContext, mUserManager);
+
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ mController = new SystemUpdatePreferenceController(mContext);
mPreference = new Preference(RuntimeEnvironment.application);
mPreference.setKey(mController.getPreferenceKey());
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
@@ -82,7 +84,7 @@
mController.updateNonIndexableKeys(keys);
- assertThat(keys.size()).isEqualTo(1);
+ assertThat(keys).hasSize(1);
}
@Test
@@ -94,8 +96,8 @@
@Test
public void updateState_shouldSetToAndroidVersion() {
- mController = new SystemUpdatePreferenceController(
- RuntimeEnvironment.application, mUserManager);
+ mController = new SystemUpdatePreferenceController(RuntimeEnvironment.application);
+
mController.updateState(mPreference);
assertThat(mPreference.getSummary())
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java
index fd48162..2f896ac 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java
@@ -35,10 +35,13 @@
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController
.SERVICE_STATE_VALUE_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController
+ .SIGNAL_STRENGTH_LABEL_ID;
+import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController
.SIGNAL_STRENGTH_VALUE_ID;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -157,6 +160,9 @@
@Test
public void initialize_updateDataStateWithPowerOff_shouldUpdateSettingAndResetSignalStrength() {
when(mServiceState.getState()).thenReturn(ServiceState.STATE_POWER_OFF);
+ when(mPersistableBundle.getBoolean(
+ CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL)).thenReturn(
+ true);
mController.initialize();
@@ -172,6 +178,9 @@
final int signalAsu = 50;
doReturn(signalDbm).when(mController).getDbm(mSignalStrength);
doReturn(signalAsu).when(mController).getAsuLevel(mSignalStrength);
+ when(mPersistableBundle.getBoolean(
+ CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL)).thenReturn(
+ true);
mController.initialize();
@@ -226,6 +235,30 @@
}
@Test
+ public void initialize_doNotShowSignalStrength_shouldRemoveSignalStrengthSetting() {
+ when(mPersistableBundle.getBoolean(
+ CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL)).thenReturn(
+ false);
+
+ mController.initialize();
+
+ verify(mDialog).removeSettingFromScreen(SIGNAL_STRENGTH_LABEL_ID);
+ verify(mDialog).removeSettingFromScreen(SIGNAL_STRENGTH_VALUE_ID);
+ }
+
+ @Test
+ public void initialize_showSignalStrengthAndIccId_shouldShowSignalStrengthAndIccIdSetting() {
+ // getConfigForSubId is nullable, so make sure the default behavior is correct
+ when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(null);
+
+ mController.initialize();
+
+ verify(mDialog).setText(eq(SIGNAL_STRENGTH_VALUE_ID), any());
+ verify(mDialog).removeSettingFromScreen(ICCID_INFO_LABEL_ID);
+ verify(mDialog).removeSettingFromScreen(ICCID_INFO_VALUE_ID);
+ }
+
+ @Test
public void initialize_showIccid_shouldSetIccidToSetting() {
final String iccid = "12351351231241";
when(mPersistableBundle.getBoolean(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
index a163a43..c75dbf4 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.Intent;
import android.os.BatteryManager;
+import android.os.PowerManager;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
@@ -83,6 +84,14 @@
}
@Test
+ public void testOnReceive_powerSaveModeChanged_listenerInvoked() {
+ mBatteryBroadcastReceiver.onReceive(mContext,
+ new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
+
+ verify(mBatteryListener).onBatteryChanged();
+ }
+
+ @Test
public void testOnReceive_batteryDataNotChanged_listenerNotInvoked() {
final String batteryLevel = Utils.getBatteryPercentage(mChargingIntent);
final String batteryStatus = Utils.getBatteryStatus(mContext.getResources(),
diff --git a/tests/robotests/src/com/android/settings/location/LocationModeTest.java b/tests/robotests/src/com/android/settings/location/LocationModeTest.java
new file mode 100644
index 0000000..0e7a9d7
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/location/LocationModeTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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
+ */
+package com.android.settings.location;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.provider.SearchIndexableResource;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.XmlTestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class LocationModeTest {
+
+ private Context mContext;
+ private LocationMode mFragment;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ mFragment = new LocationMode();
+ }
+
+ @Test
+ public void testSearchIndexProvider_shouldIndexResource() {
+ final List<SearchIndexableResource> indexRes =
+ mFragment.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex(mContext,
+ true /* enabled */);
+
+ assertThat(indexRes).isNotNull();
+ assertThat(indexRes.get(0).xmlResId).isEqualTo(mFragment.getPreferenceScreenResId());
+ }
+
+ @Test
+ @Config(qualifiers = "mcc999")
+ public void testSearchIndexProvider_ifPageDisabled_shouldNotIndexResource() {
+ final List<String> niks = LocationMode.SEARCH_INDEX_DATA_PROVIDER
+ .getNonIndexableKeys(mContext);
+ final int xmlId = mFragment.getPreferenceScreenResId();
+
+ final List<String> keys = XmlTestUtils.getKeysFromPreferenceXml(mContext, xmlId);
+ assertThat(niks).containsAllIn(keys);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/location/RecentLocationRequestPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/RecentLocationRequestPreferenceControllerTest.java
index 5d7cca4..a1268d0 100644
--- a/tests/robotests/src/com/android/settings/location/RecentLocationRequestPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/location/RecentLocationRequestPreferenceControllerTest.java
@@ -41,7 +41,7 @@
import com.android.settings.SettingsActivity;
import com.android.settings.TestConfig;
import com.android.settings.applications.InstalledAppDetails;
-import com.android.settings.applications.AppInfoDashboardFragment;
+import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.core.FeatureFlags;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.AppPreference;
diff --git a/tests/robotests/src/com/android/settings/notification/VisibilityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/VisibilityPreferenceControllerTest.java
index cdd1e9e..c18372c 100644
--- a/tests/robotests/src/com/android/settings/notification/VisibilityPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/VisibilityPreferenceControllerTest.java
@@ -205,10 +205,11 @@
RestrictedDropDownPreference pref = mock(RestrictedDropDownPreference.class);
mController.updateState(pref);
- ArgumentCaptor<String[]> argumentCaptor = ArgumentCaptor.forClass(String[].class);
+ ArgumentCaptor<CharSequence[]> argumentCaptor =
+ ArgumentCaptor.forClass(CharSequence[].class);
verify(pref, times(1)).setEntryValues(argumentCaptor.capture());
- assertFalse(Arrays.asList(argumentCaptor.getValue())
- .contains(VISIBILITY_NO_OVERRIDE));
+ assertFalse(toStringList(argumentCaptor.getValue())
+ .contains(String.valueOf(VISIBILITY_NO_OVERRIDE)));
}
@Test
@@ -223,10 +224,11 @@
RestrictedDropDownPreference pref = mock(RestrictedDropDownPreference.class);
mController.updateState(pref);
- ArgumentCaptor<String[]> argumentCaptor = ArgumentCaptor.forClass(String[].class);
+ ArgumentCaptor<CharSequence[]> argumentCaptor =
+ ArgumentCaptor.forClass(CharSequence[].class);
verify(pref, times(1)).setEntryValues(argumentCaptor.capture());
- assertFalse(Arrays.asList(argumentCaptor.getValue())
- .contains(VISIBILITY_NO_OVERRIDE));
+ assertFalse(toStringList(argumentCaptor.getValue())
+ .contains(String.valueOf(VISIBILITY_NO_OVERRIDE)));
}
@Test
@@ -238,15 +240,24 @@
RestrictedDropDownPreference pref = mock(RestrictedDropDownPreference.class);
mController.updateState(pref);
- ArgumentCaptor<String[]> argumentCaptor = ArgumentCaptor.forClass(String[].class);
+ ArgumentCaptor<CharSequence[]> argumentCaptor =
+ ArgumentCaptor.forClass(CharSequence[].class);
verify(pref, times(1)).setEntryValues(argumentCaptor.capture());
- List<String> values = Arrays.asList(argumentCaptor.getValue());
+ List<String> values = toStringList(argumentCaptor.getValue());
assertEquals(3, values.size());
assertTrue(values.contains(String.valueOf(VISIBILITY_NO_OVERRIDE)));
assertTrue(values.contains(String.valueOf(Notification.VISIBILITY_PRIVATE)));
assertTrue(values.contains(String.valueOf(Notification.VISIBILITY_SECRET)));
}
+ private static List<String> toStringList(CharSequence[] charSequences) {
+ List<String> result = new ArrayList<>();
+ for (CharSequence charSequence : charSequences) {
+ result.add(charSequence.toString());
+ }
+ return result;
+ }
+
@Test
public void testUpdateState_noChannelOverride() throws Exception {
Settings.Secure.putInt(mContext.getContentResolver(),
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
index 20a05e3..8628678 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockSettingsHelperTest.java
@@ -131,9 +131,7 @@
public void testLaunchConfirmationActivity_internal_shouldPropagateTheme() {
Intent intent = new Intent()
.putExtra(WizardManagerHelper.EXTRA_THEME, WizardManagerHelper.THEME_GLIF_V2);
- Activity activity = Robolectric.buildActivity(Activity.class)
- .withIntent(intent)
- .get();
+ Activity activity = Robolectric.buildActivity(Activity.class, intent).get();
ChooseLockSettingsHelper helper = getChooseLockSettingsHelper(activity);
helper.launchConfirmationActivity(123, "test title", true, 0 /* userId */);
diff --git a/tests/robotests/src/com/android/settings/search/SearchIndexProviderCodeInspector.java b/tests/robotests/src/com/android/settings/search/SearchIndexProviderCodeInspector.java
index a8372d9..f84f9a2 100644
--- a/tests/robotests/src/com/android/settings/search/SearchIndexProviderCodeInspector.java
+++ b/tests/robotests/src/com/android/settings/search/SearchIndexProviderCodeInspector.java
@@ -43,13 +43,13 @@
"SettingsPreferenceFragment should implement Indexable, but these do not:\n";
private static final String NOT_CONTAINING_PROVIDER_OBJECT_ERROR =
"Indexable should have public field "
- + DatabaseIndexingManager.FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER
+ + DatabaseIndexingUtils.FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER
+ " but these are not:\n";
private static final String NOT_SHARING_PREF_CONTROLLERS_BETWEEN_FRAG_AND_PROVIDER =
"DashboardFragment should share pref controllers with its SearchIndexProvider, but "
+ " these are not: \n";
private static final String NOT_IN_INDEXABLE_PROVIDER_REGISTRY =
- "Class containing " + DatabaseIndexingManager.FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER
+ "Class containing " + DatabaseIndexingUtils.FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER
+ " must be added to " + SearchIndexableResources.class.getName()
+ " but these are not: \n";
private static final String NOT_PROVIDING_VALID_RESOURCE_ERROR =
@@ -173,7 +173,7 @@
private boolean hasSearchIndexProvider(Class clazz) {
try {
final Field f = clazz.getField(
- DatabaseIndexingManager.FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER);
+ DatabaseIndexingUtils.FIELD_NAME_SEARCH_INDEX_DATA_PROVIDER);
return f != null;
} catch (NoClassDefFoundError e) {
// Cannot find class def, ignore
diff --git a/tests/robotests/src/com/android/settings/search/XmlParserUtilTest.java b/tests/robotests/src/com/android/settings/search/XmlParserUtilTest.java
index 6050b32..2bec503 100644
--- a/tests/robotests/src/com/android/settings/search/XmlParserUtilTest.java
+++ b/tests/robotests/src/com/android/settings/search/XmlParserUtilTest.java
@@ -129,6 +129,16 @@
}
@Test
+ @Config(qualifiers = "mcc999")
+ public void testControllerAttribute_returnsValidData() {
+ XmlResourceParser parser = getChildByType(R.xml.about_legal, "Preference");
+ final AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ String controller = XmlParserUtils.getController(mContext, attrs);
+ assertThat(controller).isEqualTo("mind_flayer");
+ }
+
+ @Test
public void testDataSummaryInvalid_ReturnsNull() {
XmlResourceParser parser = getParentPrimedParser(R.xml.display_settings);
final AttributeSet attrs = Xml.asAttributeSet(parser);
diff --git a/tests/robotests/src/com/android/settings/slices/SliceDataTest.java b/tests/robotests/src/com/android/settings/slices/SliceDataTest.java
new file mode 100644
index 0000000..0e4acca
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/slices/SliceDataTest.java
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.slices;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.net.Uri;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class SliceDataTest {
+
+ private final String KEY = "KEY";
+ private final String TITLE = "title";
+ private final String SUMMARY = "summary";
+ private final String SCREEN_TITLE = "screen title";
+ private final String FRAGMENT_NAME = "fragment name";
+ private final int ICON = 1234; // I declare a thumb war
+ private final Uri URI = Uri.parse("content://com.android.settings.slices/test");
+ private final String PREF_CONTROLLER = "com.android.settings.slices.tester";
+
+ @Test
+ public void testBuilder_buildsMatchingObject() {
+ SliceData.Builder builder = new SliceData.Builder()
+ .setKey(KEY)
+ .setTitle(TITLE)
+ .setSummary(SUMMARY)
+ .setScreenTitle(SCREEN_TITLE)
+ .setIcon(ICON)
+ .setFragmentName(FRAGMENT_NAME)
+ .setUri(URI)
+ .setPreferenceControllerClassName(PREF_CONTROLLER);
+
+ SliceData data = builder.build();
+
+ assertThat(data.getKey()).isEqualTo(KEY);
+ assertThat(data.getTitle()).isEqualTo(TITLE);
+ assertThat(data.getSummary()).isEqualTo(SUMMARY);
+ assertThat(data.getScreenTitle()).isEqualTo(SCREEN_TITLE);
+ assertThat(data.getIconResource()).isEqualTo(ICON);
+ assertThat(data.getFragmentClassName()).isEqualTo(FRAGMENT_NAME);
+ assertThat(data.getUri()).isEqualTo(URI);
+ assertThat(data.getPreferenceController()).isEqualTo(PREF_CONTROLLER);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testBuilder_noKey_throwsIllegalStateException() {
+ new SliceData.Builder()
+ .setTitle(TITLE)
+ .setSummary(SUMMARY)
+ .setScreenTitle(SCREEN_TITLE)
+ .setIcon(ICON)
+ .setFragmentName(FRAGMENT_NAME)
+ .setUri(URI)
+ .setPreferenceControllerClassName(PREF_CONTROLLER)
+ .build();
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testBuilder_noTitle_throwsIllegalStateException() {
+ new SliceData.Builder()
+ .setKey(KEY)
+ .setSummary(SUMMARY)
+ .setScreenTitle(SCREEN_TITLE)
+ .setIcon(ICON)
+ .setFragmentName(FRAGMENT_NAME)
+ .setUri(URI)
+ .setPreferenceControllerClassName(PREF_CONTROLLER)
+ .build();
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testBuilder_noFragment_throwsIllegalStateException() {
+ new SliceData.Builder()
+ .setKey(KEY)
+ .setFragmentName(FRAGMENT_NAME)
+ .setSummary(SUMMARY)
+ .setScreenTitle(SCREEN_TITLE)
+ .setIcon(ICON)
+ .setUri(URI)
+ .setPreferenceControllerClassName(PREF_CONTROLLER)
+ .build();
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testBuilder_noUri_throwsIllegalStateException() {
+ new SliceData.Builder()
+ .setKey(KEY)
+ .setTitle(TITLE)
+ .setSummary(SUMMARY)
+ .setScreenTitle(SCREEN_TITLE)
+ .setIcon(ICON)
+ .setFragmentName(FRAGMENT_NAME)
+ .setPreferenceControllerClassName(PREF_CONTROLLER)
+ .build();
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testBuilder_noPrefController_throwsIllegalStateException() {
+ new SliceData.Builder()
+ .setKey(KEY)
+ .setTitle(TITLE)
+ .setSummary(SUMMARY)
+ .setScreenTitle(SCREEN_TITLE)
+ .setIcon(ICON)
+ .setUri(URI)
+ .setFragmentName(FRAGMENT_NAME)
+ .build();
+ }
+
+ @Test
+ public void testBuilder_noSubtitle_buildsMatchingObject() {
+ SliceData.Builder builder = new SliceData.Builder()
+ .setKey(KEY)
+ .setTitle(TITLE)
+ .setScreenTitle(SCREEN_TITLE)
+ .setIcon(ICON)
+ .setFragmentName(FRAGMENT_NAME)
+ .setUri(URI)
+ .setPreferenceControllerClassName(PREF_CONTROLLER);
+
+ SliceData data = builder.build();
+
+ assertThat(data.getKey()).isEqualTo(KEY);
+ assertThat(data.getTitle()).isEqualTo(TITLE);
+ assertThat(data.getSummary()).isNull();
+ assertThat(data.getScreenTitle()).isEqualTo(SCREEN_TITLE);
+ assertThat(data.getIconResource()).isEqualTo(ICON);
+ assertThat(data.getFragmentClassName()).isEqualTo(FRAGMENT_NAME);
+ assertThat(data.getUri()).isEqualTo(URI);
+ assertThat(data.getPreferenceController()).isEqualTo(PREF_CONTROLLER);
+ }
+
+ @Test
+ public void testBuilder_noScreenTitle_buildsMatchingObject() {
+ SliceData.Builder builder = new SliceData.Builder()
+ .setKey(KEY)
+ .setTitle(TITLE)
+ .setSummary(SUMMARY)
+ .setIcon(ICON)
+ .setFragmentName(FRAGMENT_NAME)
+ .setUri(URI)
+ .setPreferenceControllerClassName(PREF_CONTROLLER);
+
+ SliceData data = builder.build();
+
+ assertThat(data.getKey()).isEqualTo(KEY);
+ assertThat(data.getTitle()).isEqualTo(TITLE);
+ assertThat(data.getSummary()).isEqualTo(SUMMARY);
+ assertThat(data.getScreenTitle()).isNull();
+ assertThat(data.getIconResource()).isEqualTo(ICON);
+ assertThat(data.getFragmentClassName()).isEqualTo(FRAGMENT_NAME);
+ assertThat(data.getUri()).isEqualTo(URI);
+ assertThat(data.getPreferenceController()).isEqualTo(PREF_CONTROLLER);
+ }
+
+ @Test
+ public void testBuilder_noIcon_buildsMatchingObject() {
+ SliceData.Builder builder = new SliceData.Builder()
+ .setKey(KEY)
+ .setTitle(TITLE)
+ .setSummary(SUMMARY)
+ .setScreenTitle(SCREEN_TITLE)
+ .setFragmentName(FRAGMENT_NAME)
+ .setUri(URI)
+ .setPreferenceControllerClassName(PREF_CONTROLLER);
+
+ SliceData data = builder.build();
+
+ assertThat(data.getKey()).isEqualTo(KEY);
+ assertThat(data.getTitle()).isEqualTo(TITLE);
+ assertThat(data.getSummary()).isEqualTo(SUMMARY);
+ assertThat(data.getScreenTitle()).isEqualTo(SCREEN_TITLE);
+ assertThat(data.getIconResource()).isEqualTo(0);
+ assertThat(data.getFragmentClassName()).isEqualTo(FRAGMENT_NAME);
+ assertThat(data.getUri()).isEqualTo(URI);
+ assertThat(data.getPreferenceController()).isEqualTo(PREF_CONTROLLER);
+ }
+
+ @Test
+ public void testEquality_identicalObjects() {
+ SliceData.Builder builder = new SliceData.Builder()
+ .setKey(KEY)
+ .setTitle(TITLE)
+ .setSummary(SUMMARY)
+ .setScreenTitle(SCREEN_TITLE)
+ .setIcon(ICON)
+ .setFragmentName(FRAGMENT_NAME)
+ .setUri(URI)
+ .setPreferenceControllerClassName(PREF_CONTROLLER);
+
+ SliceData dataOne = builder.build();
+ SliceData dataTwo = builder.build();
+
+ assertThat(dataOne.hashCode()).isEqualTo(dataTwo.hashCode());
+ assertThat(dataOne).isEqualTo(dataTwo);
+ }
+
+ @Test
+ public void testEquality_matchingKey_EqualObjects() {
+ SliceData.Builder builder = new SliceData.Builder()
+ .setKey(KEY)
+ .setTitle(TITLE)
+ .setSummary(SUMMARY)
+ .setScreenTitle(SCREEN_TITLE)
+ .setIcon(ICON)
+ .setFragmentName(FRAGMENT_NAME)
+ .setUri(URI)
+ .setPreferenceControllerClassName(PREF_CONTROLLER);
+
+ SliceData dataOne = builder.build();
+
+ builder.setTitle(TITLE + " diff")
+ .setSummary(SUMMARY + " diff")
+ .setScreenTitle(SCREEN_TITLE + " diff")
+ .setIcon(ICON + 1)
+ .setFragmentName(FRAGMENT_NAME + " diff")
+ .setUri(URI)
+ .setPreferenceControllerClassName(PREF_CONTROLLER + " diff");
+
+ SliceData dataTwo = builder.build();
+
+ assertThat(dataOne.hashCode()).isEqualTo(dataTwo.hashCode());
+ assertThat(dataOne).isEqualTo(dataTwo);
+ }
+
+ @Test
+ public void testEquality_differentKey_differentObjects() {
+ SliceData.Builder builder = new SliceData.Builder()
+ .setKey(KEY)
+ .setTitle(TITLE)
+ .setSummary(SUMMARY)
+ .setScreenTitle(SCREEN_TITLE)
+ .setIcon(ICON)
+ .setFragmentName(FRAGMENT_NAME)
+ .setUri(URI)
+ .setPreferenceControllerClassName(PREF_CONTROLLER);
+
+ SliceData dataOne = builder.build();
+
+ builder.setKey("not key");
+ SliceData dataTwo = builder.build();
+
+ assertThat(dataOne.hashCode()).isNotEqualTo(dataTwo.hashCode());
+ assertThat(dataOne).isNotEqualTo(dataTwo);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java
new file mode 100644
index 0000000..a4020dd
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java
@@ -0,0 +1,87 @@
+package com.android.settings.slices;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+
+import com.android.settings.TestConfig;
+import com.android.settings.slices.SlicesDatabaseHelper.IndexColumns;
+import com.android.settings.testutils.DatabaseTestUtils;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class SlicesDatabaseHelperTest {
+
+ private Context mContext;
+ private SlicesDatabaseHelper mSlicesDatabaseHelper;
+ private SQLiteDatabase mDatabase;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mSlicesDatabaseHelper = new SlicesDatabaseHelper(mContext);
+ mDatabase = mSlicesDatabaseHelper.getWritableDatabase();
+ }
+
+ @After
+ public void cleanUp() {
+ DatabaseTestUtils.clearDb(mContext);
+ }
+
+ @Test
+ public void testDatabaseSchema() {
+ Cursor cursor = mDatabase.rawQuery("SELECT * FROM slices_index", null);
+ String[] columnNames = cursor.getColumnNames();
+
+ String[] expectedNames = new String[]{
+ IndexColumns.KEY,
+ IndexColumns.TITLE,
+ IndexColumns.SUBTITLE,
+ IndexColumns.SCREENTITLE,
+ IndexColumns.ICON_RESOURCE,
+ IndexColumns.FRAGMENT,
+ IndexColumns.CONTROLLER
+ };
+
+ assertThat(columnNames).isEqualTo(expectedNames);
+ }
+
+ @Test
+ public void testUpgrade_dropsOldData() {
+ ContentValues dummyValues = getDummyRow();
+
+ mDatabase.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, dummyValues);
+ Cursor baseline = mDatabase.rawQuery("SELECT * FROM slices_index", null);
+ assertThat(baseline.getCount()).isEqualTo(1);
+
+ mSlicesDatabaseHelper.onUpgrade(mDatabase, 0, 1);
+
+ Cursor newCursor = mDatabase.rawQuery("SELECT * FROM slices_index", null);
+ assertThat(newCursor.getCount()).isEqualTo(0);
+ }
+
+ private ContentValues getDummyRow() {
+ ContentValues values;
+
+ values = new ContentValues();
+ values.put(IndexColumns.KEY, "key");
+ values.put(IndexColumns.TITLE, "title");
+ values.put(IndexColumns.SUBTITLE, "subtitle");
+ values.put(IndexColumns.ICON_RESOURCE, 99);
+ values.put(IndexColumns.FRAGMENT, "fragmentClassName");
+ values.put(IndexColumns.CONTROLLER, "preferenceController");
+
+ return values;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/SettingsRobolectricTestRunner.java b/tests/robotests/src/com/android/settings/testutils/SettingsRobolectricTestRunner.java
index 2e8bac0..7c374e9 100644
--- a/tests/robotests/src/com/android/settings/testutils/SettingsRobolectricTestRunner.java
+++ b/tests/robotests/src/com/android/settings/testutils/SettingsRobolectricTestRunner.java
@@ -62,8 +62,8 @@
// By adding any resources from libraries we need the AndroidManifest, we can access
// them from within the parallel universe's resource loader.
- final AndroidManifest manifest = new AndroidManifest(Fs.fileFromPath(manifestPath),
- Fs.fileFromPath(resDir), Fs.fileFromPath(assetsDir)) {
+ return new AndroidManifest(Fs.fileFromPath(manifestPath), Fs.fileFromPath(resDir),
+ Fs.fileFromPath(assetsDir), "com.android.settings") {
@Override
public List<ResourcePath> getIncludedResourcePaths() {
List<ResourcePath> paths = super.getIncludedResourcePaths();
@@ -71,10 +71,6 @@
return paths;
}
};
-
- // Set the package name to the renamed one
- manifest.setPackageName("com.android.settings");
- return manifest;
}
public static void getIncludedResourcePaths(String packageName, List<ResourcePath> paths) {
diff --git a/tests/unit/AndroidManifest.xml b/tests/unit/AndroidManifest.xml
index 65ed661..b22c01b 100644
--- a/tests/unit/AndroidManifest.xml
+++ b/tests/unit/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
diff --git a/tests/unit/src/com/android/settings/applications/AppOpsSettingsTest.java b/tests/unit/src/com/android/settings/applications/AppOpsSettingsTest.java
new file mode 100644
index 0000000..d89d4a3
--- /dev/null
+++ b/tests/unit/src/com/android/settings/applications/AppOpsSettingsTest.java
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+package com.android.settings.applications;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.Direction;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+import android.support.v7.widget.RecyclerView;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.app.AppOpsManager.MODE_ERRORED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * An abstract parent for testing settings activities that manage an AppOps permission.
+ */
+abstract public class AppOpsSettingsTest {
+ private static final String WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard";
+ private static final long START_ACTIVITY_TIMEOUT = 5000;
+
+ private Context mContext;
+ private UiDevice mUiDevice;
+ private PackageManager mPackageManager;
+ private AppOpsManager mAppOpsManager;
+ private List<UserInfo> mProfiles;
+ private String mPackageName;
+
+ // These depend on which app op's settings UI is being tested.
+ private final String mActivityAction;
+ private final int mAppOpCode;
+
+ protected AppOpsSettingsTest(String activityAction, int appOpCode) {
+ mActivityAction = activityAction;
+ mAppOpCode = appOpCode;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mPackageName = InstrumentationRegistry.getContext().getPackageName();
+ mPackageManager = mContext.getPackageManager();
+ mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+ mProfiles = mContext.getSystemService(UserManager.class).getProfiles(UserHandle.myUserId());
+ resetAppOpModeForAllProfiles();
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ mUiDevice.wakeUp();
+ mUiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND);
+ }
+
+ private void resetAppOpModeForAllProfiles() throws Exception {
+ for (UserInfo user : mProfiles) {
+ final int uid = mPackageManager.getPackageUidAsUser(mPackageName, user.id);
+ mAppOpsManager.setMode(mAppOpCode, uid, mPackageName, MODE_DEFAULT);
+ }
+ }
+
+ /**
+ * Creates an intent for showing the permission settings for all apps.
+ */
+ private Intent createManageAllAppsIntent() {
+ return new Intent(mActivityAction);
+ }
+
+ /**
+ * Creates an intent for showing the permission setting for a single app.
+ */
+ private Intent createManageSingleAppIntent(String packageName) {
+ final Intent intent = createManageAllAppsIntent();
+ intent.setData(Uri.parse("package:" + packageName));
+ return intent;
+ }
+
+ private String getApplicationLabel(String packageName) throws Exception {
+ final ApplicationInfo info = mPackageManager.getApplicationInfo(packageName, 0);
+ return mPackageManager.getApplicationLabel(info).toString();
+ }
+
+ private UiObject2 findAndVerifySwitchState(boolean checked) {
+ final BySelector switchSelector = By.clazz(Switch.class).res("android:id/switch_widget");
+ final UiObject2 switchPref = mUiDevice.wait(Until.findObject(switchSelector),
+ START_ACTIVITY_TIMEOUT);
+ assertNotNull("Switch not shown", switchPref);
+ assertTrue("Switch in invalid state", switchPref.isChecked() == checked);
+ return switchPref;
+ }
+
+ @Test
+ public void testAppList() throws Exception {
+ final String testAppLabel = getApplicationLabel(mPackageName);
+
+ mContext.startActivity(createManageAllAppsIntent());
+ final BySelector preferenceListSelector =
+ By.clazz(RecyclerView.class).res("com.android.settings:id/apps_list");
+ final UiObject2 preferenceList = mUiDevice.wait(Until.findObject(preferenceListSelector),
+ START_ACTIVITY_TIMEOUT);
+ assertNotNull("App list not shown", preferenceList);
+
+ final BySelector appLabelTextViewSelector = By.clazz(TextView.class)
+ .res("android:id/title")
+ .text(testAppLabel);
+ List<UiObject2> listOfMatchingTextViews;
+ do {
+ listOfMatchingTextViews = preferenceList.findObjects(appLabelTextViewSelector);
+ // assuming the number of profiles will be sufficiently small so that all the entries
+ // for the same package will fit in one screen at some time during the scroll.
+ } while (listOfMatchingTextViews.size() != mProfiles.size() &&
+ preferenceList.scroll(Direction.DOWN, 0.2f));
+ assertEquals("Test app not listed for each profile", mProfiles.size(),
+ listOfMatchingTextViews.size());
+
+ for (UiObject2 matchingObject : listOfMatchingTextViews) {
+ matchingObject.click();
+ findAndVerifySwitchState(true);
+ mUiDevice.pressBack();
+ }
+ }
+
+ private void testAppDetailScreenForAppOp(int appOpMode, int userId) throws Exception {
+ final String testAppLabel = getApplicationLabel(mPackageName);
+ final BySelector appDetailTitleSelector = By.clazz(TextView.class)
+ .res("com.android.settings:id/app_detail_title")
+ .text(testAppLabel);
+
+ mAppOpsManager.setMode(mAppOpCode,
+ mPackageManager.getPackageUidAsUser(mPackageName, userId), mPackageName, appOpMode);
+ mContext.startActivityAsUser(createManageSingleAppIntent(mPackageName),
+ UserHandle.of(userId));
+ mUiDevice.wait(Until.findObject(appDetailTitleSelector), START_ACTIVITY_TIMEOUT);
+ findAndVerifySwitchState(appOpMode == MODE_ALLOWED || appOpMode == MODE_DEFAULT);
+ mUiDevice.pressBack();
+ }
+
+ @Test
+ public void testSingleApp() throws Exception {
+ // App op MODE_DEFAULT is already tested in #testAppList
+ for (UserInfo user : mProfiles) {
+ testAppDetailScreenForAppOp(MODE_ALLOWED, user.id);
+ testAppDetailScreenForAppOp(MODE_ERRORED, user.id);
+ }
+ }
+
+ private void testSwitchToggle(int fromAppOp, int toAppOp) throws Exception {
+ final int packageUid = mPackageManager.getPackageUid(mPackageName, 0);
+ final boolean initialState = (fromAppOp == MODE_ALLOWED || fromAppOp == MODE_DEFAULT);
+
+ mAppOpsManager.setMode(mAppOpCode, packageUid, mPackageName, fromAppOp);
+ mContext.startActivity(createManageSingleAppIntent(mPackageName));
+ final UiObject2 switchPref = findAndVerifySwitchState(initialState);
+ switchPref.click();
+ Thread.sleep(1000);
+ assertEquals("Toggling switch did not change app op", toAppOp,
+ mAppOpsManager.checkOpNoThrow(mAppOpCode, packageUid,
+ mPackageName));
+ mUiDevice.pressBack();
+ }
+
+ @Test
+ public void testIfSwitchTogglesAppOp() throws Exception {
+ testSwitchToggle(MODE_ALLOWED, MODE_ERRORED);
+ testSwitchToggle(MODE_ERRORED, MODE_ALLOWED);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mUiDevice.pressHome();
+ resetAppOpModeForAllProfiles();
+ }
+}
diff --git a/tests/unit/src/com/android/settings/applications/DrawOverlaySettingsTest.java b/tests/unit/src/com/android/settings/applications/DrawOverlaySettingsTest.java
new file mode 100644
index 0000000..24760ae
--- /dev/null
+++ b/tests/unit/src/com/android/settings/applications/DrawOverlaySettingsTest.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.applications;
+
+import android.app.AppOpsManager;
+import android.provider.Settings;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class DrawOverlaySettingsTest extends AppOpsSettingsTest {
+
+ public DrawOverlaySettingsTest() {
+ super(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, AppOpsManager.OP_SYSTEM_ALERT_WINDOW);
+ }
+
+ // Test cases are in the superclass.
+}
\ No newline at end of file
diff --git a/tests/unit/src/com/android/settings/applications/ExternalSourcesSettingsTest.java b/tests/unit/src/com/android/settings/applications/ExternalSourcesSettingsTest.java
index 82f0e0a..6ac21af 100644
--- a/tests/unit/src/com/android/settings/applications/ExternalSourcesSettingsTest.java
+++ b/tests/unit/src/com/android/settings/applications/ExternalSourcesSettingsTest.java
@@ -16,185 +16,21 @@
package com.android.settings.applications;
-import static android.app.AppOpsManager.MODE_ALLOWED;
-import static android.app.AppOpsManager.MODE_DEFAULT;
-import static android.app.AppOpsManager.MODE_ERRORED;
-import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
import android.app.AppOpsManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
-import android.net.Uri;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.Direction;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
-import android.widget.ListView;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.List;
-
@RunWith(AndroidJUnit4.class)
@LargeTest
-public class ExternalSourcesSettingsTest {
+public class ExternalSourcesSettingsTest extends AppOpsSettingsTest {
- private static final String TAG = ExternalSourcesSettingsTest.class.getSimpleName();
- private static final String WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard";
- private static final long START_ACTIVITY_TIMEOUT = 5000;
-
- private Context mContext;
- private UiDevice mUiDevice;
- private PackageManager mPackageManager;
- private AppOpsManager mAppOpsManager;
- private List<UserInfo> mProfiles;
- private String mPackageName;
-
- @Before
- public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getTargetContext();
- mPackageName = InstrumentationRegistry.getContext().getPackageName();
- mPackageManager = mContext.getPackageManager();
- mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
- mProfiles = mContext.getSystemService(UserManager.class).getProfiles(UserHandle.myUserId());
- resetAppOpModeForAllProfiles();
- mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- mUiDevice.wakeUp();
- mUiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND);
+ public ExternalSourcesSettingsTest() {
+ super(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
+ AppOpsManager.OP_REQUEST_INSTALL_PACKAGES);
}
- private void resetAppOpModeForAllProfiles() throws Exception {
- for (UserInfo user : mProfiles) {
- final int uid = mPackageManager.getPackageUidAsUser(mPackageName, user.id);
- mAppOpsManager.setMode(OP_REQUEST_INSTALL_PACKAGES, uid, mPackageName, MODE_DEFAULT);
- }
- }
-
- private Intent createManageExternalSourcesListIntent() {
- final Intent manageExternalSourcesIntent = new Intent();
- manageExternalSourcesIntent.setAction(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
- return manageExternalSourcesIntent;
- }
-
- private Intent createManageExternalSourcesAppIntent(String packageName) {
- final Intent intent = createManageExternalSourcesListIntent();
- intent.setData(Uri.parse("package:" + packageName));
- return intent;
- }
-
- private String getApplicationLabel(String packageName) throws Exception {
- final ApplicationInfo info = mPackageManager.getApplicationInfo(packageName, 0);
- return mPackageManager.getApplicationLabel(info).toString();
- }
-
- private UiObject2 findAndVerifySwitchState(boolean checked) {
- final BySelector switchSelector = By.clazz(Switch.class).res("android:id/switch_widget");
- final UiObject2 switchPref = mUiDevice.wait(Until.findObject(switchSelector),
- START_ACTIVITY_TIMEOUT);
- assertNotNull("Switch not shown", switchPref);
- assertTrue("Switch in invalid state", switchPref.isChecked() == checked);
- return switchPref;
- }
-
- @Test
- public void testManageExternalSourcesList() throws Exception {
- final String testAppLabel = getApplicationLabel(mPackageName);
-
- mContext.startActivity(createManageExternalSourcesListIntent());
- final BySelector preferenceListSelector = By.clazz(ListView.class).res("android:id/list");
- final UiObject2 preferenceList = mUiDevice.wait(Until.findObject(preferenceListSelector),
- START_ACTIVITY_TIMEOUT);
- assertNotNull("App list not shown", preferenceList);
-
- final BySelector appLabelTextViewSelector = By.clazz(TextView.class)
- .res("android:id/title")
- .text(testAppLabel);
- List<UiObject2> listOfMatchingTextViews;
- do {
- listOfMatchingTextViews = preferenceList.findObjects(appLabelTextViewSelector);
- // assuming the number of profiles will be sufficiently small so that all the entries
- // for the same package will fit in one screen at some time during the scroll.
- } while (listOfMatchingTextViews.size() != mProfiles.size() &&
- preferenceList.scroll(Direction.DOWN, 0.2f));
- assertEquals("Test app not listed for each profile", mProfiles.size(),
- listOfMatchingTextViews.size());
-
- for (UiObject2 matchingObject : listOfMatchingTextViews) {
- matchingObject.click();
- findAndVerifySwitchState(true);
- mUiDevice.pressBack();
- }
- }
-
- private void testAppDetailScreenForAppOp(int appOpMode, int userId) throws Exception {
- final String testAppLabel = getApplicationLabel(mPackageName);
- final BySelector appDetailTitleSelector = By.clazz(TextView.class)
- .res("com.android.settings:id/app_detail_title")
- .text(testAppLabel);
-
- mAppOpsManager.setMode(OP_REQUEST_INSTALL_PACKAGES,
- mPackageManager.getPackageUidAsUser(mPackageName, userId), mPackageName, appOpMode);
- mContext.startActivityAsUser(createManageExternalSourcesAppIntent(mPackageName),
- UserHandle.of(userId));
- mUiDevice.wait(Until.findObject(appDetailTitleSelector), START_ACTIVITY_TIMEOUT);
- findAndVerifySwitchState(appOpMode == MODE_ALLOWED || appOpMode == MODE_DEFAULT);
- mUiDevice.pressBack();
- }
-
- @Test
- public void testManageExternalSourcesForApp() throws Exception {
- // App op MODE_DEFAULT is already tested in #testManageExternalSourcesList
- for (UserInfo user : mProfiles) {
- testAppDetailScreenForAppOp(MODE_ALLOWED, user.id);
- testAppDetailScreenForAppOp(MODE_ERRORED, user.id);
- }
- }
-
- private void testSwitchToggle(int fromAppOp, int toAppOp) throws Exception {
- final int packageUid = mPackageManager.getPackageUid(mPackageName, 0);
- final boolean initialState = (fromAppOp == MODE_ALLOWED || fromAppOp == MODE_DEFAULT);
-
- mAppOpsManager.setMode(OP_REQUEST_INSTALL_PACKAGES, packageUid, mPackageName, fromAppOp);
- mContext.startActivity(createManageExternalSourcesAppIntent(mPackageName));
- final UiObject2 switchPref = findAndVerifySwitchState(initialState);
- switchPref.click();
- Thread.sleep(1000);
- assertEquals("Toggling switch did not change app op", toAppOp,
- mAppOpsManager.checkOpNoThrow(OP_REQUEST_INSTALL_PACKAGES, packageUid,
- mPackageName));
- mUiDevice.pressBack();
- }
-
- @Test
- public void testIfSwitchTogglesAppOp() throws Exception {
- testSwitchToggle(MODE_ALLOWED, MODE_ERRORED);
- testSwitchToggle(MODE_ERRORED, MODE_ALLOWED);
- }
-
- @After
- public void tearDown() throws Exception {
- mUiDevice.pressHome();
- resetAppOpModeForAllProfiles();
- }
+ // Test cases are in the superclass.
}
diff --git a/tests/unit/src/com/android/settings/applications/PackageUtilTest.java b/tests/unit/src/com/android/settings/applications/PackageUtilTest.java
index 1c064ae..0e3c402 100644
--- a/tests/unit/src/com/android/settings/applications/PackageUtilTest.java
+++ b/tests/unit/src/com/android/settings/applications/PackageUtilTest.java
@@ -35,6 +35,7 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
+@Deprecated
public class PackageUtilTest {
private static final String ALL_USERS_APP_NAME = "com.google.allusers.app";
private static final String ONE_USER_APP_NAME = "com.google.oneuser.app";
diff --git a/tests/unit/src/com/android/settings/applications/SpecialAppAccessSettingsTest.java b/tests/unit/src/com/android/settings/applications/SpecialAppAccessSettingsTest.java
new file mode 100644
index 0000000..4165d06
--- /dev/null
+++ b/tests/unit/src/com/android/settings/applications/SpecialAppAccessSettingsTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+package com.android.settings.applications;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.test.filters.SmallTest;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiScrollable;
+import android.support.test.uiautomator.UiSelector;
+import android.test.InstrumentationTestCase;
+import android.widget.TextView;
+
+import com.android.settings.R;
+
+import org.junit.Test;
+
+/**
+ * Test for Special App Access preferences.
+ */
+@SmallTest
+public class SpecialAppAccessSettingsTest extends InstrumentationTestCase {
+
+ private UiDevice mDevice;
+ private Context mTargetContext;
+ private String mTargetPackage;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ mTargetContext = getInstrumentation().getTargetContext();
+ mTargetPackage = mTargetContext.getPackageName();
+ }
+
+ @Test
+ public void testSelectPictureInPicture_shouldNotCrash() throws Exception {
+ launchSpecialApps();
+ final String titlePictureInPictureApp =
+ mTargetContext.getResources().getString(R.string.picture_in_picture_title);
+
+ // select Picture-in-Picture
+ mDevice.findObject(new UiSelector().text(titlePictureInPictureApp)).click();
+
+ // Picture-in-picture settings page should launch and no crash
+ final UiObject actionBar = mDevice.findObject(new UiSelector().resourceId(
+ "com.android.settings:id/action_bar"));
+ final UiObject title = actionBar.getChild(
+ new UiSelector().className(TextView.class.getName()));
+ assertEquals(titlePictureInPictureApp, title.getText());
+ }
+
+ private void launchSpecialApps() throws Exception {
+ final Intent settingsIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .setPackage(mTargetPackage)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ getInstrumentation().getContext().startActivity(settingsIntent);
+ final String titleApps = mTargetContext.getResources().getString(
+ R.string.app_and_notification_dashboard_title);
+ mDevice.findObject(new UiSelector().text(titleApps)).click();
+ final String titleAdvance = mTargetContext.getResources().getString(
+ R.string.advanced_section_header);
+ mDevice.findObject(new UiSelector().text(titleAdvance)).click();
+ final String titleSpecialApps = mTargetContext.getResources().getString(
+ R.string.special_access);
+
+ try {
+ // scollbar may or may not be present, depending on how many recents app are there. If
+ // the page is scrollable, scroll to the bottom to show the special app access settings.
+ final UiScrollable settings = new UiScrollable(
+ new UiSelector().packageName(mTargetContext.getPackageName()).scrollable(true));
+ settings.scrollTextIntoView(titleSpecialApps);
+ } catch (UiObjectNotFoundException e) {
+ // ignore
+ }
+
+ mDevice.findObject(new UiSelector().text(titleSpecialApps)).click();
+ }
+
+}
diff --git a/tests/unit/src/com/android/settings/display/ThemePreferenceControllerTest.java b/tests/unit/src/com/android/settings/display/ThemePreferenceControllerTest.java
index 69c8c54..fe8203c 100644
--- a/tests/unit/src/com/android/settings/display/ThemePreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/display/ThemePreferenceControllerTest.java
@@ -118,8 +118,8 @@
}
return info;
});
- PackageInfo pi = new PackageInfo();
- pi.isStaticOverlay = true;
+ PackageInfo pi = mock(PackageInfo.class);
+ when(pi.isStaticOverlayPackage()).thenReturn(true);
when(mMockPackageManager.getPackageInfo(eq("com.android.Theme1"), anyInt())).thenReturn(pi);
when(mMockPackageManager.getPackageInfo(eq("com.android.Theme2"), anyInt())).thenReturn(
new PackageInfo());
diff --git a/tests/unit/src/com/android/settings/vpn2/PreferenceListTest.java b/tests/unit/src/com/android/settings/vpn2/PreferenceListTest.java
index bb12efa..2accbf2 100644
--- a/tests/unit/src/com/android/settings/vpn2/PreferenceListTest.java
+++ b/tests/unit/src/com/android/settings/vpn2/PreferenceListTest.java
@@ -36,9 +36,9 @@
import java.util.Map;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.compat.ArgumentMatcher;
public class PreferenceListTest extends AndroidTestCase {
private static final String TAG = "PreferenceListTest";
@@ -135,13 +135,10 @@
/* lockdownVpnKey */ null);
updater.run();
- final ArgumentMatcher<VpnProfile> equalsFake = new ArgumentMatcher<VpnProfile>() {
- @Override
- public boolean matchesObject(final Object arg) {
- if (arg == vpnProfile) return true;
- if (arg == null) return false;
- return TextUtils.equals(((VpnProfile) arg).key, vpnProfile.key);
- }
+ final ArgumentMatcher<VpnProfile> equalsFake = arg -> {
+ if (arg == vpnProfile) return true;
+ if (arg == null) return false;
+ return TextUtils.equals(arg.key, vpnProfile.key);
};
// The VPN profile should have been used to create a preference and set up at laest once