Snap for 7447849 from 2c40af09e4 to sc-v2-release
Change-Id: I237aca49394221401b194339a7bb4d6df471a265
This commit is contained in:
@@ -1117,22 +1117,6 @@
|
||||
column="5"/>
|
||||
</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=" <color name="contextual_card_stroke_color">#1f000000</color>"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="res/values/colors.xml"
|
||||
line="106"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="HardCodedColor"
|
||||
severity="Error"
|
||||
@@ -4285,22 +4269,6 @@
|
||||
column="44"/>
|
||||
</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 name="strokeColor">@color/contextual_card_stroke_color</item>"
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="res/values/styles.xml"
|
||||
line="475"
|
||||
column="34"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="HardCodedColor"
|
||||
severity="Error"
|
||||
|
||||
@@ -20,15 +20,15 @@
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:pathData="M21.5,9.39l-1.63,0l0.81,-1.42l-0.86,-0.5l-0.82,1.42l-0.82,-1.42l-0.86,0.5l0.81,1.42l-1.63,0l0,1l1.63,0l-0.81,1.41l0.86,0.5l0.82,-1.41l0.82,1.41l0.86,-0.5l-0.81,-1.41l1.63,0z" />
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:pathData="M13.68,7.97l-0.86,-0.5l-0.82,1.42l-0.82,-1.42l-0.86,0.5l0.81,1.42l-1.63,0l0,1l1.63,0l-0.81,1.41l0.86,0.5l0.82,-1.41l0.82,1.41l0.86,-0.5l-0.81,-1.41l1.63,0l0,-1l-1.63,0z" />
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:pathData="M6.68,7.97l-0.86,-0.5l-0.82,1.42l-0.82,-1.42l-0.86,0.5l0.81,1.42l-1.63,0l0,1l1.63,0l-0.81,1.41l0.86,0.5l0.82,-1.41l0.82,1.41l0.86,-0.5l-0.81,-1.41l1.63,0l0,-1l-1.63,0z" />
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:pathData="M21,17.89H3c-0.28,0 -0.5,-0.22 -0.5,-0.5v-1c0,-0.28 0.22,-0.5 0.5,-0.5h18c0.28,0 0.5,0.22 0.5,0.5v1C21.5,17.66 21.28,17.89 21,17.89z" />
|
||||
</vector>
|
||||
|
||||
@@ -20,18 +20,18 @@
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:pathData="M4,4m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0" />
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:pathData="M4,12m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0" />
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:pathData="M12,4m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0" />
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:pathData="M20,12m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0" />
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:pathData="M20,18c-0.93,0 -1.7,0.64 -1.93,1.5h-4.14c-0.22,-0.86 -1,-1.5 -1.93,-1.5s-1.7,0.64 -1.93,1.5H5.93c-0.05,-0.18 -0.12,-0.35 -0.21,-0.51l5.28,-5.28C11.29,13.89 11.63,14 12,14c1.1,0 2,-0.9 2,-2c0,-0.37 -0.11,-0.71 -0.28,-1.01l5.28,-5.28C19.29,5.89 19.63,6 20,6c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2c0,0.37 0.11,0.71 0.28,1.01l-5.28,5.28C12.71,10.11 12.37,10 12,10c-1.1,0 -2,0.9 -2,2c0,0.37 0.11,0.71 0.28,1.01l-5.28,5.28C4.71,18.11 4.37,18 4,18c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c0.93,0 1.7,-0.64 1.93,-1.5h4.14c0.22,0.86 1,1.5 1.93,1.5s1.7,-0.64 1.93,-1.5h4.14c0.22,0.86 1,1.5 1.93,1.5c1.1,0 2,-0.9 2,-2S21.1,18 20,18z" />
|
||||
</vector>
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/colorAccent"
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:pathData="M20,4L4,4A2,2 0,0 0,2 6L2,18a2,2 0,0 0,2 2L20,20a2,2 0,0 0,2 -2L22,6A2,2 0,0 0,20 4ZM7.1,15L5.9,15L5.9,10.2L4.7,10.2L4.7,9L7.1,9v6ZM13.2,11.4A1.2,1.2 0,0 1,12 12.6L10.8,12.6v1.2h2.4L13.2,15L9.6,15L9.6,12.6a1.2,1.2 0,0 1,1.2 -1.2L12,11.4L12,10.2L9.6,10.2L9.6,9L12,9a1.2,1.2 0,0 1,1.2 1.2v1.2ZM19.3,11.1a0.9,0.9 0,0 1,-0.9 0.9,0.9 0.9,0 0,1 0.9,0.9v0.9A1.2,1.2 0,0 1,18.1 15L15.7,15L15.7,13.8h2.4L18.1,12.6L16.9,12.6L16.9,11.4h1.2L18.1,10.2L15.7,10.2L15.7,9h2.4a1.2,1.2 0,0 1,1.2 1.2v0.9Z" />
|
||||
</vector>
|
||||
|
||||
25
res/drawable/ic_upload.xml
Normal file
25
res/drawable/ic_upload.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
~ Copyright (C) 2021 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24.0dp"
|
||||
android:height="24.0dp"
|
||||
android:tint="?android:attr/colorControlNormal"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M18,15v3H6v-3H4v3c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-3H18z M7,9l1.41,1.41L11,7.83V16h2V7.83l2.59,2.58L17,9l-5-5L7,9z" />
|
||||
</vector>
|
||||
@@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<layer-list
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
|
||||
|
||||
<item
|
||||
android:id="@android:id/background">
|
||||
<shape>
|
||||
<corners android:radius="8dp" />
|
||||
<solid android:color="?androidprv:attr/colorSurfaceVariant" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@android:id/progress">
|
||||
<clip>
|
||||
<shape>
|
||||
<corners android:radius="8dp" />
|
||||
<solid android:color="?android:attr/textColorPrimary" />
|
||||
</shape>
|
||||
</clip>
|
||||
</item>
|
||||
</layer-list>
|
||||
140
res/layout-land/request_manage_credentials.xml
Normal file
140
res/layout-land/request_manage_credentials.xml
Normal file
@@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (C) 2021 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.
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:weightSum="2">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
style="@style/RequestManageCredentialsHeaderLandscape">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/credential_management_app_icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:contentDescription="@null" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/credential_management_app_title"
|
||||
style="@style/RequestManageCredentialsTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/credential_management_app_description"
|
||||
style="@style/RequestManageCredentialsDescription"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/request_manage_credentials_description" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="true">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/apps_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/button_panel"
|
||||
style="@style/RequestManageCredentialsButtonPanel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<Button
|
||||
android:id="@+id/dont_allow_button"
|
||||
style="@style/RequestManageCredentialsDontAllowButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/request_manage_credentials_dont_allow" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/allow_button"
|
||||
style="@style/RequestManageCredentialsAllowButton"
|
||||
android:theme="@style/RoundedCornerButtonTheme"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/request_manage_credentials_allow" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/extended_fab"
|
||||
style="@style/RequestManageCredentialsFab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/request_manage_credentials_more"
|
||||
android:theme="@style/Theme.CollapsingToolbar.Settings"
|
||||
app:backgroundTint="?android:attr/colorAccent"
|
||||
app:elevation="3dp"
|
||||
app:icon="@drawable/ic_arrow_downward"
|
||||
app:iconTint="?android:attr/textColorPrimary"
|
||||
app:layout_anchor="@id/apps_list"
|
||||
app:layout_anchorGravity="bottom|center" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -29,6 +29,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="-8dp"
|
||||
layout="@layout/preference_material" />
|
||||
layout="@layout/settingslib_preference" />
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="12dp">
|
||||
android:layout_marginTop="-32dp">
|
||||
|
||||
<com.google.android.setupdesign.view.IllustrationVideoView
|
||||
android:id="@+id/illustration_default"
|
||||
@@ -51,11 +51,13 @@
|
||||
<com.airbnb.lottie.LottieAnimationView
|
||||
android:id="@+id/illustration_lottie"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="340dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:visibility="invisible"
|
||||
android:layout_height="400dp"
|
||||
android:layout_marginTop="-48dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:visibility="gone"
|
||||
app:lottie_autoPlay="true"
|
||||
app:lottie_loop="true" />
|
||||
app:lottie_loop="true"
|
||||
app:lottie_speed="1.5" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/illustration_accessibility"
|
||||
|
||||
@@ -20,13 +20,14 @@
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button"
|
||||
android:text="@string/remove_account_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="20dip"
|
||||
android:layout_marginBottom="12dip"
|
||||
android:gravity="center" />
|
||||
android:id="@+id/button"
|
||||
android:text="@string/remove_account_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:gravity="center"
|
||||
style="@style/ActionPrimaryButton" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
<Button
|
||||
android:id="@+id/allow_button"
|
||||
style="@style/RequestManageCredentialsAllowButton"
|
||||
android:theme="@style/RoundedCornerButtonTheme"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/request_manage_credentials_allow"/>
|
||||
@@ -70,8 +71,8 @@
|
||||
app:layout_anchorGravity="bottom|center"
|
||||
app:elevation="3dp"
|
||||
app:icon="@drawable/ic_arrow_downward"
|
||||
app:iconTint="?android:attr/colorAccent"
|
||||
app:backgroundTint="?android:attr/colorPrimary"
|
||||
app:iconTint="?android:attr/textColorPrimary"
|
||||
app:backgroundTint="?android:attr/colorAccent"
|
||||
android:theme="@style/Theme.CollapsingToolbar.Settings"/>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
@@ -103,9 +103,7 @@
|
||||
<color name="homepage_wallpaper_background">#E51AD1</color>
|
||||
<color name="homepage_notification_background">#DD4C9D</color>
|
||||
|
||||
<color name="contextual_card_stroke_color">#1f000000</color>
|
||||
<color name="contextual_card_dismissal_background">@*android:color/material_grey_100</color>
|
||||
<color name="contextual_card_background">@*android:color/background_device_default_light</color>
|
||||
<!-- End of dashboard/homepage icon background colors -->
|
||||
|
||||
<color name="switchbar_background_color">@*android:color/material_grey_600</color>
|
||||
|
||||
@@ -856,8 +856,6 @@
|
||||
<!-- Button text in face settings which lets the user enroll their face [CHAR LIMIT=40] -->
|
||||
<string name="security_settings_face_settings_enroll">Set up Face Unlock</string>
|
||||
<!-- Text shown in face settings explaining what your face can be used for. [CHAR LIMIT=NONE] -->
|
||||
<string name="security_settings_face_settings_top_intro">Use Face Unlock to unlock your device, sign in to apps, and confirm payments.</string>
|
||||
<!-- Text shown in face settings explaining what your face can be used for. [CHAR LIMIT=NONE] -->
|
||||
<string name="security_settings_face_settings_footer">Use your face to unlock your phone or for authentication in apps, like when you sign in or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face.\n\nYour phone can be unlocked by someone who looks a lot like you, like an identical sibling.</string>
|
||||
<!-- Text shown in face settings explaining what your face can be used for. Used when attention checking is not supported. [CHAR LIMIT=NONE] -->
|
||||
<string name="security_settings_face_settings_footer_attention_not_supported">Use your face to unlock your phone or for authentication in apps, like when you sign in or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face, even if your eyes are closed.\n\nYour phone can be unlocked by someone who looks a lot like you, like an identical sibling.</string>
|
||||
@@ -6791,9 +6789,9 @@
|
||||
<string name="cert_not_installed">Certificate not installed</string>
|
||||
|
||||
<!-- Title of screen shown to the user when an app requests to manage the user's KeyChain credentials [CHAR LIMIT=NONE] -->
|
||||
<string name="request_manage_credentials_title">Allow <xliff:g id="app_name" example="Ping">%s</xliff:g> to install certificates on this device?</string>
|
||||
<string name="request_manage_credentials_title">Allow <b><xliff:g id="app_name" example="Ping">^1</xliff:g></b> to install certificates on this device?</string>
|
||||
<!-- Description of screen shown to the user when an app requests to manage the user's KeyChain credentials [CHAR LIMIT=NONE] -->
|
||||
<string name="request_manage_credentials_description">These certificates will identify you to the apps and URLs below</string>
|
||||
<string name="request_manage_credentials_description">These certificates will verify you by sharing your device\u2019s unique ID with the apps and URLs below</string>
|
||||
<!-- Label for button to not allow an app to manage the user's KeyChain credentials [CHAR_LIMIT=50] -->
|
||||
<string name="request_manage_credentials_dont_allow">Don\u2019t allow</string>
|
||||
<!-- Label for button to allow an app to manage the user's KeyChain credentials [CHAR_LIMIT=50] -->
|
||||
@@ -6805,7 +6803,9 @@
|
||||
<!-- Summary if there is no certificate management app [CHAR_LIMIT=NONE] -->
|
||||
<string name="no_certificate_management_app">None</string>
|
||||
<!-- Summary of preference if there is a certificate management app [CHAR LIMIT=NONE] -->
|
||||
<string name="certificate_management_app_description">Certificates installed by this app identify you to the apps and URLs below</string>
|
||||
<string name="certificate_management_app_description">Certificates will verify you when you use the apps and URLs below</string>
|
||||
<!-- Label for button to uninstall all certificates installed by the credential management app [CHAR LIMIT=30] -->
|
||||
<string name="uninstall_certs_credential_management_app">Uninstall certificates</string>
|
||||
<!-- Label for button to remove the credential management app [CHAR LIMIT=30] -->
|
||||
<string name="remove_credential_management_app">Remove</string>
|
||||
<!-- List item found in the credential management app's authentication policy [CHAR LIMIT=NONE] -->
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<resources
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
|
||||
|
||||
<style name="Widget.ActionBar.Base"
|
||||
parent="@android:style/Widget.DeviceDefault.Light.ActionBar.Solid"/>
|
||||
@@ -404,12 +405,6 @@
|
||||
<item name="android:progressDrawable">@drawable/ring_progress</item>
|
||||
</style>
|
||||
|
||||
<style name="HorizontalProgressBarStyle"
|
||||
parent="android:style/Widget.Material.ProgressBar.Horizontal">
|
||||
<item name="android:progressDrawable">@drawable/progress_horizontal</item>
|
||||
<item name="android:scaleY">0.5</item>
|
||||
</style>
|
||||
|
||||
<style name="ActionPrimaryButton" parent="android:Widget.DeviceDefault.Button.Colored">
|
||||
<item name="android:theme">@style/RoundedCornerThemeOverlay</item>
|
||||
</style>
|
||||
@@ -417,6 +412,8 @@
|
||||
|
||||
<style name="RoundedCornerThemeOverlay">
|
||||
<item name="android:buttonCornerRadius">24dp</item>
|
||||
<item name="android:paddingStart">16dp</item>
|
||||
<item name="android:paddingEnd">16dp</item>
|
||||
</style>
|
||||
|
||||
<style name="LockPatternContainerStyle">
|
||||
@@ -470,11 +467,9 @@
|
||||
<item name="android:layout_marginBottom">@dimen/contextual_card_vertical_margin</item>
|
||||
<item name="android:layout_marginStart">@dimen/contextual_card_side_margin</item>
|
||||
<item name="android:layout_marginEnd">@dimen/contextual_card_side_margin</item>
|
||||
<item name="cardBackgroundColor">@color/contextual_card_background</item>
|
||||
<item name="cardBackgroundColor">?androidprv:attr/colorSurface</item>
|
||||
<item name="cardCornerRadius">@dimen/contextual_card_corner_radius</item>
|
||||
<item name="cardElevation">0dp</item>
|
||||
<item name="strokeColor">@color/contextual_card_stroke_color</item>
|
||||
<item name="strokeWidth">1dp</item>
|
||||
<item name="rippleColor">?android:attr/colorControlHighlight</item>
|
||||
</style>
|
||||
|
||||
@@ -799,10 +794,19 @@
|
||||
<item name="android:background">?android:colorBackground</item>
|
||||
</style>
|
||||
|
||||
<style name="RoundedCornerButtonTheme">
|
||||
<item name="android:buttonCornerRadius">50dp</item>
|
||||
<item name="android:paddingStart">20dp</item>
|
||||
<item name="android:paddingEnd">20dp</item>
|
||||
<item name="android:paddingTop">18dp</item>
|
||||
<item name="android:paddingBottom">18dp</item>
|
||||
</style>
|
||||
|
||||
<style name="RequestManageCredentialsAllowButton" parent="@style/ActionPrimaryButton">
|
||||
<item name="android:fontFamily">google-sans-medium</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="RequestManageCredentialsDontAllowButton"
|
||||
@@ -810,13 +814,13 @@
|
||||
<item name="android:fontFamily">google-sans-medium</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:textColor">?android:attr/colorAccent</item>
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="RequestManageCredentialsFab">
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:textColor">?android:attr/colorAccent</item>
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
<item name="android:layout_marginBottom">12dp</item>
|
||||
</style>
|
||||
|
||||
@@ -828,6 +832,13 @@
|
||||
<item name="android:orientation">vertical</item>
|
||||
</style>
|
||||
|
||||
<style name="RequestManageCredentialsHeaderLandscape">
|
||||
<item name="android:paddingStart">24dp</item>
|
||||
<item name="android:paddingEnd">24dp</item>
|
||||
<item name="android:paddingTop">24dp</item>
|
||||
<item name="android:paddingBottom">24dp</item>
|
||||
</style>
|
||||
|
||||
<style name="RequestManageCredentialsTitle">
|
||||
<item name="android:layout_marginTop">24dp</item>
|
||||
<item name="android:textSize">36sp</item>
|
||||
@@ -838,6 +849,7 @@
|
||||
<item name="android:layout_marginTop">24dp</item>
|
||||
<item name="android:textSize">18sp</item>
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
<item name="android:alpha">0.7</item>
|
||||
</style>
|
||||
|
||||
<style name="AppAuthenticationPolicyItem">
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
<item name="android:homeAsUpIndicator">@drawable/ic_arrow_back</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="android:datePickerDialogTheme">@style/PickerDialogTheme.Settings</item>
|
||||
<item name="android:progressBarStyleHorizontal">@style/HorizontalProgressBarStyle</item>
|
||||
|
||||
<item name="fingerprint_layout_theme">@style/FingerprintLayoutTheme</item>
|
||||
<item name="face_layout_theme">@style/FaceLayoutTheme</item>
|
||||
|
||||
@@ -27,19 +27,11 @@
|
||||
android:order="-10000"
|
||||
settings:controller="com.android.settings.security.CredentialManagementAppHeaderController"/>
|
||||
|
||||
<com.android.settingslib.widget.TopIntroPreference
|
||||
android:key="top_intro_request_manage_credentials"
|
||||
android:order="-9999"
|
||||
android:title="@string/request_manage_credentials_description"
|
||||
settings:searchable="false"/>
|
||||
|
||||
<!-- Buttons -->
|
||||
<com.android.settingslib.widget.ActionButtonsPreference
|
||||
android:key="buttons"
|
||||
android:selectable="true"
|
||||
android:order="-9998"
|
||||
settings:allowDividerAbove="true"
|
||||
settings:allowDividerBelow="true"
|
||||
settings:controller="com.android.settings.security.CredentialManagementAppButtonsController"/>
|
||||
|
||||
<!-- Authentication Policy -->
|
||||
@@ -47,7 +39,6 @@
|
||||
android:key="authentication_policy"
|
||||
android:layout="@layout/preference_category_no_label"
|
||||
android:title="@string/summary_placeholder"
|
||||
settings:allowDividerAbove="true"
|
||||
settings:controller="com.android.settings.security.CredentialManagementAppPolicyController"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
@@ -19,10 +19,6 @@
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:title="@string/security_settings_face_preference_title">
|
||||
|
||||
<com.android.settingslib.widget.TopIntroPreference
|
||||
android:title="@string/security_settings_face_settings_top_intro"
|
||||
settings:searchable="false"/>
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="security_settings_face_unlock_category"
|
||||
android:title="@string/security_settings_face_settings_use_face_category"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:title="@string/storage_settings">
|
||||
<Preference
|
||||
<com.android.settings.widget.CardPreference
|
||||
android:key="free_up_space"
|
||||
android:order="4"
|
||||
android:title="@string/storage_free_up_space_title"
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
android:icon="@drawable/ic_storage"
|
||||
android:order="3"
|
||||
settings:controller="com.android.settings.deviceinfo.storage.AutomaticStorageManagementSwitchPreferenceController"/>
|
||||
<Preference
|
||||
<com.android.settings.widget.CardPreference
|
||||
android:key="free_up_space"
|
||||
android:order="4"
|
||||
android:title="@string/storage_free_up_space_title"
|
||||
|
||||
@@ -118,7 +118,8 @@ public class AppBatteryPreferenceController extends BasePreferenceController
|
||||
final UserManager userManager =
|
||||
(UserManager) mContext.getSystemService(Context.USER_SERVICE);
|
||||
final BatteryEntry entry = new BatteryEntry(mContext, /* handler */null, userManager,
|
||||
mUidBatteryConsumer, /* isHidden */ false, /* packages */ null, mPackageName);
|
||||
mUidBatteryConsumer, /* isHidden */ false,
|
||||
mUidBatteryConsumer.getUid(), /* packages */ null, mPackageName);
|
||||
AdvancedPowerUsageDetail.startBatteryDetailPage(mParent.getActivity(), mParent,
|
||||
entry, mBatteryPercent);
|
||||
} else {
|
||||
|
||||
@@ -39,6 +39,8 @@ import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.google.android.setupcompat.template.FooterButton;
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
import com.google.android.setupdesign.span.LinkSpan;
|
||||
import com.google.android.setupdesign.template.RequireScrollMixin;
|
||||
import com.google.android.setupdesign.template.RequireScrollMixin.OnRequireScrollStateChangedListener;
|
||||
import com.google.android.setupdesign.util.DynamicColorPalette;
|
||||
|
||||
/**
|
||||
@@ -180,6 +182,35 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
launchConfirmLock(getConfirmLockTitleResId());
|
||||
}
|
||||
}
|
||||
|
||||
FooterButton primaryButton = getPrimaryFooterButton();
|
||||
FooterButton secondaryButton = getSecondaryFooterButton();
|
||||
if (primaryButton == null) {
|
||||
Log.d(TAG, "getPrimaryFooterButton() was null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (secondaryButton == null) {
|
||||
Log.d(TAG, "getSecondaryFooterButton() was null");
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup scroll mixin
|
||||
final RequireScrollMixin requireScrollMixin = getLayout().getMixin(
|
||||
RequireScrollMixin.class);
|
||||
requireScrollMixin.requireScrollWithButton(this, primaryButton, getScrollCompletedText(),
|
||||
this::onNextButtonClick);
|
||||
|
||||
secondaryButton.setVisibility(View.INVISIBLE);
|
||||
requireScrollMixin.setOnRequireScrollStateChangedListener(
|
||||
new OnRequireScrollStateChangedListener() {
|
||||
@Override
|
||||
public void onRequireScrollStateChanged(boolean scrollNeeded) {
|
||||
if (!scrollNeeded && secondaryButton.getVisibility() == View.INVISIBLE) {
|
||||
secondaryButton.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -335,4 +366,18 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
|
||||
}
|
||||
return mIconColorFilter;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected FooterButton getPrimaryFooterButton() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected FooterButton getSecondaryFooterButton() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected int getScrollCompletedText() {
|
||||
return R.string.security_settings_face_enroll_introduction_more;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import com.google.android.setupcompat.template.FooterBarMixin;
|
||||
import com.google.android.setupcompat.template.FooterButton;
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
import com.google.android.setupdesign.span.LinkSpan;
|
||||
import com.google.android.setupdesign.template.RequireScrollMixin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -81,32 +80,6 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
mFaceFeatureProvider = FeatureFactory.getFactory(getApplicationContext())
|
||||
.getFaceFeatureProvider();
|
||||
|
||||
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
|
||||
mFooterBarMixin.setSecondaryButton(
|
||||
new FooterButton.Builder(this)
|
||||
.setText(R.string.security_settings_face_enroll_introduction_no_thanks)
|
||||
.setListener(this::onSkipButtonClick)
|
||||
.setButtonType(FooterButton.ButtonType.NEXT)
|
||||
.setTheme(R.style.SudGlifButton_Primary)
|
||||
.build(),
|
||||
true /* usePrimaryStyle */);
|
||||
|
||||
FooterButton.Builder nextButtonBuilder = new FooterButton.Builder(this)
|
||||
.setText(R.string.security_settings_face_enroll_introduction_agree)
|
||||
.setButtonType(FooterButton.ButtonType.OPT_IN)
|
||||
.setTheme(R.style.SudGlifButton_Primary);
|
||||
if (maxFacesEnrolled()) {
|
||||
nextButtonBuilder.setListener(this::onNextButtonClick);
|
||||
mFooterBarMixin.setPrimaryButton(nextButtonBuilder.build());
|
||||
} else {
|
||||
final FooterButton agreeButton = nextButtonBuilder.build();
|
||||
mFooterBarMixin.setPrimaryButton(agreeButton);
|
||||
final RequireScrollMixin requireScrollMixin = getLayout().getMixin(
|
||||
RequireScrollMixin.class);
|
||||
requireScrollMixin.requireScrollWithButton(this, agreeButton,
|
||||
R.string.security_settings_face_enroll_introduction_more,
|
||||
this::onNextButtonClick);
|
||||
}
|
||||
|
||||
// This path is an entry point for SetNewPasswordController, e.g.
|
||||
// adb shell am start -a android.app.action.SET_NEW_PASSWORD
|
||||
@@ -232,4 +205,40 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
public void onClick(LinkSpan span) {
|
||||
// TODO(b/110906762)
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FooterButton getPrimaryFooterButton() {
|
||||
if (mFooterBarMixin == null) {
|
||||
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
|
||||
}
|
||||
|
||||
if (mFooterBarMixin.getPrimaryButton() == null) {
|
||||
final FooterButton nextButtonBuilder = new FooterButton.Builder(this)
|
||||
.setText(R.string.security_settings_face_enroll_introduction_agree)
|
||||
.setButtonType(FooterButton.ButtonType.OPT_IN)
|
||||
.setListener(this::onNextButtonClick)
|
||||
.setTheme(R.style.SudGlifButton_Primary)
|
||||
.build();
|
||||
mFooterBarMixin.setPrimaryButton(nextButtonBuilder);
|
||||
}
|
||||
return mFooterBarMixin.getPrimaryButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FooterButton getSecondaryFooterButton() {
|
||||
if (mFooterBarMixin == null) {
|
||||
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
|
||||
}
|
||||
|
||||
if (mFooterBarMixin.getSecondaryButton() == null) {
|
||||
final FooterButton noThanksButton = new FooterButton.Builder(this)
|
||||
.setText(R.string.security_settings_face_enroll_introduction_no_thanks)
|
||||
.setListener(this::onSkipButtonClick)
|
||||
.setButtonType(FooterButton.ButtonType.NEXT)
|
||||
.setTheme(R.style.SudGlifButton_Primary)
|
||||
.build();
|
||||
mFooterBarMixin.setSecondaryButton(noThanksButton, true /* usePrimaryStyle */);
|
||||
}
|
||||
return mFooterBarMixin.getSecondaryButton();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
import com.google.android.setupcompat.template.FooterBarMixin;
|
||||
import com.google.android.setupcompat.template.FooterButton;
|
||||
import com.google.android.setupdesign.span.LinkSpan;
|
||||
import com.google.android.setupdesign.template.RequireScrollMixin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -69,29 +68,6 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
iconDelete.getDrawable().setColorFilter(getIconColorFilter());
|
||||
iconInfo.getDrawable().setColorFilter(getIconColorFilter());
|
||||
iconLink.getDrawable().setColorFilter(getIconColorFilter());
|
||||
|
||||
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
|
||||
mFooterBarMixin.setSecondaryButton(
|
||||
new FooterButton.Builder(this)
|
||||
.setText(getNegativeButtonTextId())
|
||||
.setListener(this::onSkipButtonClick)
|
||||
.setButtonType(FooterButton.ButtonType.NEXT)
|
||||
.setTheme(R.style.SudGlifButton_Primary)
|
||||
.build(),
|
||||
true /* usePrimaryStyle */);
|
||||
|
||||
final FooterButton nextButton = new FooterButton.Builder(this)
|
||||
.setText(R.string.security_settings_fingerprint_enroll_introduction_agree)
|
||||
.setListener(this::onNextButtonClick)
|
||||
.setButtonType(FooterButton.ButtonType.OPT_IN)
|
||||
.setTheme(R.style.SudGlifButton_Primary)
|
||||
.build();
|
||||
|
||||
mFooterBarMixin.setPrimaryButton(nextButton);
|
||||
final RequireScrollMixin requireScrollMixin =
|
||||
getLayout().getMixin(RequireScrollMixin.class);
|
||||
requireScrollMixin.requireScrollWithButton(this, nextButton,
|
||||
R.string.security_settings_face_enroll_introduction_more, this::onNextButtonClick);
|
||||
}
|
||||
|
||||
int getNegativeButtonTextId() {
|
||||
@@ -216,4 +192,45 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FooterButton getPrimaryFooterButton() {
|
||||
if (mFooterBarMixin == null) {
|
||||
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
|
||||
}
|
||||
|
||||
if (mFooterBarMixin.getPrimaryButton() == null) {
|
||||
final FooterButton nextButtonBuilder = new FooterButton.Builder(this)
|
||||
.setText(R.string.security_settings_fingerprint_enroll_introduction_agree)
|
||||
.setListener(this::onNextButtonClick)
|
||||
.setButtonType(FooterButton.ButtonType.OPT_IN)
|
||||
.setTheme(R.style.SudGlifButton_Primary)
|
||||
.build();
|
||||
mFooterBarMixin.setPrimaryButton(nextButtonBuilder);
|
||||
}
|
||||
return mFooterBarMixin.getPrimaryButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FooterButton getSecondaryFooterButton() {
|
||||
if (mFooterBarMixin == null) {
|
||||
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
|
||||
}
|
||||
|
||||
if (mFooterBarMixin.getSecondaryButton() == null) {
|
||||
final FooterButton noThanksButton = new FooterButton.Builder(this)
|
||||
.setText(getNegativeButtonTextId())
|
||||
.setListener(this::onSkipButtonClick)
|
||||
.setButtonType(FooterButton.ButtonType.NEXT)
|
||||
.setTheme(R.style.SudGlifButton_Primary)
|
||||
.build();
|
||||
mFooterBarMixin.setSecondaryButton(noThanksButton, true /* usePrimaryStyle */);
|
||||
}
|
||||
return mFooterBarMixin.getSecondaryButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getScrollCompletedText() {
|
||||
return R.string.security_settings_face_enroll_introduction_more;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.SubSettings;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
import com.android.settingslib.transition.SettingsTransitionHelper.TransitionType;
|
||||
|
||||
@@ -181,8 +182,10 @@ public class SubSettingLauncher {
|
||||
|
||||
@VisibleForTesting
|
||||
void launchAsUser(Intent intent, UserHandle userHandle) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
if (!Utils.isPageTransitionEnabled(mContext)) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
}
|
||||
mContext.startActivityAsUser(intent, userHandle);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,15 +16,25 @@
|
||||
|
||||
package com.android.settings.display;
|
||||
|
||||
import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
|
||||
import static android.provider.Settings.Secure.CAMERA_AUTOROTATE;
|
||||
|
||||
import static com.android.settings.display.SmartAutoRotateController.hasSufficientPermission;
|
||||
import static com.android.settings.display.SmartAutoRotateController.isRotationResolverServiceAvailable;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.hardware.SensorPrivacyManager;
|
||||
import android.os.PowerManager;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.view.RotationPolicy;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
@@ -41,8 +51,21 @@ public class SmartAutoRotatePreferenceController extends BasePreferenceControlle
|
||||
private RotationPolicy.RotationPolicyListener mRotationPolicyListener;
|
||||
private Preference mPreference;
|
||||
|
||||
private final SensorPrivacyManager mPrivacyManager;
|
||||
private final PowerManager mPowerManager;
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
refreshSummary(mPreference);
|
||||
}
|
||||
};
|
||||
|
||||
public SmartAutoRotatePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mPrivacyManager = SensorPrivacyManager.getInstance(context);
|
||||
mPrivacyManager
|
||||
.addSensorPrivacyListener(CAMERA, (sensor, enabled) -> refreshSummary(mPreference));
|
||||
mPowerManager = context.getSystemService(PowerManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,6 +82,8 @@ public class SmartAutoRotatePreferenceController extends BasePreferenceControlle
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
mContext.registerReceiver(mReceiver,
|
||||
new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
|
||||
if (mRotationPolicyListener == null) {
|
||||
mRotationPolicyListener = new RotationPolicy.RotationPolicyListener() {
|
||||
@Override
|
||||
@@ -75,12 +100,27 @@ public class SmartAutoRotatePreferenceController extends BasePreferenceControlle
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
mContext.unregisterReceiver(mReceiver);
|
||||
if (mRotationPolicyListener != null) {
|
||||
RotationPolicy.unregisterRotationPolicyListener(mContext,
|
||||
mRotationPolicyListener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Need this because all controller tests use Roboelectric. No easy way to mock this service,
|
||||
* so we mock the call we need
|
||||
*/
|
||||
@VisibleForTesting
|
||||
boolean isCameraLocked() {
|
||||
return mPrivacyManager.isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean isPowerSaveMode() {
|
||||
return mPowerManager.isPowerSaveMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
int activeStringId = R.string.auto_rotate_option_off;
|
||||
@@ -89,7 +129,11 @@ public class SmartAutoRotatePreferenceController extends BasePreferenceControlle
|
||||
mContext.getContentResolver(),
|
||||
CAMERA_AUTOROTATE,
|
||||
0, UserHandle.USER_CURRENT);
|
||||
activeStringId = cameraRotate == 1 ? R.string.auto_rotate_option_face_based
|
||||
activeStringId = cameraRotate == 1 && isRotationResolverServiceAvailable(mContext)
|
||||
&& hasSufficientPermission(mContext)
|
||||
&& !isCameraLocked()
|
||||
&& !isPowerSaveMode()
|
||||
? R.string.auto_rotate_option_face_based
|
||||
: R.string.auto_rotate_option_on;
|
||||
}
|
||||
return mContext.getString(activeStringId);
|
||||
|
||||
@@ -55,6 +55,7 @@ import com.android.settingslib.core.lifecycle.events.OnPause;
|
||||
import com.android.settingslib.utils.StringUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -66,6 +67,7 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro
|
||||
static final boolean USE_FAKE_DATA = false;
|
||||
private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 20;
|
||||
private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
|
||||
private static final String MEDIASERVER_PACKAGE_NAME = "mediaserver";
|
||||
|
||||
private final String mPreferenceKey;
|
||||
@VisibleForTesting
|
||||
@@ -303,27 +305,17 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro
|
||||
final ArrayList<BatteryEntry> results = new ArrayList<>();
|
||||
final List<UidBatteryConsumer> uidBatteryConsumers =
|
||||
mBatteryUsageStats.getUidBatteryConsumers();
|
||||
|
||||
// Sort to have all apps with "real" UIDs first, followed by apps that are supposed
|
||||
// to be combined with the real ones.
|
||||
uidBatteryConsumers.sort(Comparator.comparingInt(
|
||||
consumer -> consumer.getUid() == getRealUid(consumer) ? 0 : 1));
|
||||
|
||||
for (int i = 0, size = uidBatteryConsumers.size(); i < size; i++) {
|
||||
final UidBatteryConsumer consumer = uidBatteryConsumers.get(i);
|
||||
int realUid = consumer.getUid();
|
||||
final int uid = getRealUid(consumer);
|
||||
|
||||
// Check if this UID is a shared GID. If so, we combine it with the OWNER's
|
||||
// actual app UID.
|
||||
if (isSharedGid(consumer.getUid())) {
|
||||
realUid = UserHandle.getUid(UserHandle.USER_SYSTEM,
|
||||
UserHandle.getAppIdFromSharedAppGid(consumer.getUid()));
|
||||
}
|
||||
|
||||
// Check if this UID is a system UID (mediaserver, logd, nfc, drm, etc).
|
||||
if (isSystemUid(realUid)
|
||||
&& !"mediaserver".equals(consumer.getPackageWithHighestDrain())) {
|
||||
// Use the system UID for all UIDs running in their own sandbox that
|
||||
// are not apps. We exclude mediaserver because we already are expected to
|
||||
// report that as a separate item.
|
||||
realUid = Process.SYSTEM_UID;
|
||||
}
|
||||
|
||||
final String[] packages = mPackageManager.getPackagesForUid(consumer.getUid());
|
||||
final String[] packages = mPackageManager.getPackagesForUid(uid);
|
||||
if (mBatteryUtils.shouldHideUidBatteryConsumerUnconditionally(consumer, packages)) {
|
||||
continue;
|
||||
}
|
||||
@@ -333,11 +325,11 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro
|
||||
continue;
|
||||
}
|
||||
|
||||
final int index = batteryEntryList.indexOfKey(realUid);
|
||||
final int index = batteryEntryList.indexOfKey(uid);
|
||||
if (index < 0) {
|
||||
// New entry.
|
||||
batteryEntryList.put(realUid, new BatteryEntry(mContext, mHandler, mUserManager,
|
||||
consumer, isHidden, packages, null, loadDataInBackground));
|
||||
batteryEntryList.put(uid, new BatteryEntry(mContext, mHandler, mUserManager,
|
||||
consumer, isHidden, uid, packages, null, loadDataInBackground));
|
||||
} else {
|
||||
// Combine BatterySippers if we already have one with this UID.
|
||||
final BatteryEntry existingSipper = batteryEntryList.valueAt(index);
|
||||
@@ -385,7 +377,8 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro
|
||||
for (int i = 0, size = userBatteryConsumers.size(); i < size; i++) {
|
||||
final UserBatteryConsumer consumer = userBatteryConsumers.get(i);
|
||||
results.add(new BatteryEntry(mContext, mHandler, mUserManager,
|
||||
consumer, /* isHidden */ true, null, null, loadDataInBackground));
|
||||
consumer, /* isHidden */ true, Process.INVALID_UID, null, null,
|
||||
loadDataInBackground));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,6 +393,27 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro
|
||||
return results;
|
||||
}
|
||||
|
||||
private int getRealUid(UidBatteryConsumer consumer) {
|
||||
int realUid = consumer.getUid();
|
||||
|
||||
// Check if this UID is a shared GID. If so, we combine it with the OWNER's
|
||||
// actual app UID.
|
||||
if (isSharedGid(consumer.getUid())) {
|
||||
realUid = UserHandle.getUid(UserHandle.USER_SYSTEM,
|
||||
UserHandle.getAppIdFromSharedAppGid(consumer.getUid()));
|
||||
}
|
||||
|
||||
// Check if this UID is a system UID (mediaserver, logd, nfc, drm, etc).
|
||||
if (isSystemUid(realUid)
|
||||
&& !MEDIASERVER_PACKAGE_NAME.equals(consumer.getPackageWithHighestDrain())) {
|
||||
// Use the system UID for all UIDs running in their own sandbox that
|
||||
// are not apps. We exclude mediaserver because we already are expected to
|
||||
// report that as a separate item.
|
||||
realUid = Process.SYSTEM_UID;
|
||||
}
|
||||
return realUid;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setUsageSummary(Preference preference, BatteryEntry entry) {
|
||||
// Only show summary when usage time is longer than one minute
|
||||
|
||||
@@ -159,12 +159,15 @@ public class BatteryEntry {
|
||||
|
||||
private final Context mContext;
|
||||
private final BatteryConsumer mBatteryConsumer;
|
||||
private final int mUid;
|
||||
private final boolean mIsHidden;
|
||||
@ConvertUtils.ConsumerType
|
||||
private final int mConsumerType;
|
||||
@BatteryConsumer.PowerComponent
|
||||
private final int mPowerComponentId;
|
||||
private long mUsageDurationMs;
|
||||
private long mTimeInForegroundMs;
|
||||
private long mTimeInBackgroundMs;
|
||||
|
||||
public String name;
|
||||
public Drawable icon;
|
||||
@@ -180,13 +183,13 @@ public class BatteryEntry {
|
||||
}
|
||||
|
||||
public BatteryEntry(Context context, Handler handler, UserManager um,
|
||||
@NonNull BatteryConsumer batteryConsumer, boolean isHidden, String[] packages,
|
||||
@NonNull BatteryConsumer batteryConsumer, boolean isHidden, int uid, String[] packages,
|
||||
String packageName) {
|
||||
this(context, handler, um, batteryConsumer, isHidden, packages, packageName, true);
|
||||
this(context, handler, um, batteryConsumer, isHidden, uid, packages, packageName, true);
|
||||
}
|
||||
|
||||
public BatteryEntry(Context context, Handler handler, UserManager um,
|
||||
@NonNull BatteryConsumer batteryConsumer, boolean isHidden, String[] packages,
|
||||
@NonNull BatteryConsumer batteryConsumer, boolean isHidden, int uid, String[] packages,
|
||||
String packageName, boolean loadDataInBackground) {
|
||||
sHandler = handler;
|
||||
mContext = context;
|
||||
@@ -196,11 +199,11 @@ public class BatteryEntry {
|
||||
mPowerComponentId = -1;
|
||||
|
||||
if (batteryConsumer instanceof UidBatteryConsumer) {
|
||||
mUid = uid;
|
||||
mConsumerType = ConvertUtils.CONSUMER_TYPE_UID_BATTERY;
|
||||
mConsumedPower = batteryConsumer.getConsumedPower();
|
||||
|
||||
UidBatteryConsumer uidBatteryConsumer = (UidBatteryConsumer) batteryConsumer;
|
||||
int uid = uidBatteryConsumer.getUid();
|
||||
if (mDefaultPackageName == null) {
|
||||
// Apps should only have one package
|
||||
if (packages != null && packages.length == 1) {
|
||||
@@ -222,7 +225,12 @@ public class BatteryEntry {
|
||||
}
|
||||
}
|
||||
getQuickNameIconForUid(uid, packages, loadDataInBackground);
|
||||
mTimeInForegroundMs =
|
||||
uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND);
|
||||
mTimeInBackgroundMs =
|
||||
uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND);
|
||||
} else if (batteryConsumer instanceof UserBatteryConsumer) {
|
||||
mUid = Process.INVALID_UID;
|
||||
mConsumerType = ConvertUtils.CONSUMER_TYPE_USER_BATTERY;
|
||||
mConsumedPower = batteryConsumer.getConsumedPower();
|
||||
final NameAndIcon nameAndIcon = getNameAndIconFromUserId(
|
||||
@@ -239,6 +247,7 @@ public class BatteryEntry {
|
||||
double appsPowerMah, long usageDurationMs) {
|
||||
mContext = context;
|
||||
mBatteryConsumer = null;
|
||||
mUid = Process.INVALID_UID;
|
||||
mIsHidden = false;
|
||||
mPowerComponentId = powerComponentId;
|
||||
mConsumedPower =
|
||||
@@ -261,6 +270,7 @@ public class BatteryEntry {
|
||||
double devicePowerMah, double appsPowerMah) {
|
||||
mContext = context;
|
||||
mBatteryConsumer = null;
|
||||
mUid = Process.INVALID_UID;
|
||||
mIsHidden = false;
|
||||
mPowerComponentId = powerComponentId;
|
||||
|
||||
@@ -438,7 +448,7 @@ public class BatteryEntry {
|
||||
*/
|
||||
public String getKey() {
|
||||
if (mBatteryConsumer instanceof UidBatteryConsumer) {
|
||||
return Integer.toString(((UidBatteryConsumer) mBatteryConsumer).getUid());
|
||||
return Integer.toString(mUid);
|
||||
} else if (mBatteryConsumer instanceof UserBatteryConsumer) {
|
||||
return "U|" + ((UserBatteryConsumer) mBatteryConsumer).getUserId();
|
||||
} else {
|
||||
@@ -482,11 +492,7 @@ public class BatteryEntry {
|
||||
* Returns the UID of the app described by this entry.
|
||||
*/
|
||||
public int getUid() {
|
||||
if (mBatteryConsumer instanceof UidBatteryConsumer) {
|
||||
return ((UidBatteryConsumer) mBatteryConsumer).getUid();
|
||||
} else {
|
||||
return Process.INVALID_UID;
|
||||
}
|
||||
return mUid;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -494,8 +500,7 @@ public class BatteryEntry {
|
||||
*/
|
||||
public long getTimeInForegroundMs() {
|
||||
if (mBatteryConsumer instanceof UidBatteryConsumer) {
|
||||
return ((UidBatteryConsumer) mBatteryConsumer).getTimeInStateMs(
|
||||
UidBatteryConsumer.STATE_FOREGROUND);
|
||||
return mTimeInForegroundMs;
|
||||
} else {
|
||||
return mUsageDurationMs;
|
||||
}
|
||||
@@ -506,8 +511,7 @@ public class BatteryEntry {
|
||||
*/
|
||||
public long getTimeInBackgroundMs() {
|
||||
if (mBatteryConsumer instanceof UidBatteryConsumer) {
|
||||
return ((UidBatteryConsumer) mBatteryConsumer).getTimeInStateMs(
|
||||
UidBatteryConsumer.STATE_BACKGROUND);
|
||||
return mTimeInBackgroundMs;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -526,9 +530,15 @@ public class BatteryEntry {
|
||||
*/
|
||||
public void add(BatteryConsumer batteryConsumer) {
|
||||
mConsumedPower += batteryConsumer.getConsumedPower();
|
||||
if (mDefaultPackageName == null && batteryConsumer instanceof UidBatteryConsumer) {
|
||||
mDefaultPackageName =
|
||||
((UidBatteryConsumer) batteryConsumer).getPackageWithHighestDrain();
|
||||
if (batteryConsumer instanceof UidBatteryConsumer) {
|
||||
UidBatteryConsumer uidBatteryConsumer = (UidBatteryConsumer) batteryConsumer;
|
||||
mTimeInForegroundMs += uidBatteryConsumer.getTimeInStateMs(
|
||||
UidBatteryConsumer.STATE_FOREGROUND);
|
||||
mTimeInBackgroundMs += uidBatteryConsumer.getTimeInStateMs(
|
||||
UidBatteryConsumer.STATE_BACKGROUND);
|
||||
if (mDefaultPackageName == null) {
|
||||
mDefaultPackageName = uidBatteryConsumer.getPackageWithHighestDrain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.location.SettingInjectorService;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.OnLifecycleEvent;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A abstract class which is responsible for creating the injected location services items.
|
||||
* Developer needs to implement the {@link #injectLocationServices(PreferenceScreen)}.
|
||||
*/
|
||||
public abstract class LocationInjectedServiceBasePreferenceController
|
||||
extends LocationBasePreferenceController implements LifecycleObserver{
|
||||
|
||||
private static final String TAG = "LocationPrefCtrl";
|
||||
@VisibleForTesting
|
||||
static final IntentFilter INTENT_FILTER_INJECTED_SETTING_CHANGED =
|
||||
new IntentFilter(SettingInjectorService.ACTION_INJECTED_SETTING_CHANGED);
|
||||
|
||||
@VisibleForTesting
|
||||
AppSettingsInjector mInjector;
|
||||
/** Receives UPDATE_INTENT */
|
||||
@VisibleForTesting
|
||||
BroadcastReceiver mInjectedSettingsReceiver;
|
||||
|
||||
public LocationInjectedServiceBasePreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(DashboardFragment fragment) {
|
||||
super.init(fragment);
|
||||
mInjector = new AppSettingsInjector(mContext, getMetricsCategory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
injectLocationServices(screen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to inject location services in preference screen.
|
||||
* @param screen
|
||||
*/
|
||||
protected abstract void injectLocationServices(PreferenceScreen screen);
|
||||
|
||||
@Override
|
||||
public void onLocationModeChanged(int mode, boolean restricted) {
|
||||
// As a safety measure, also reloads on location mode change to ensure the settings are
|
||||
// up-to-date even if an affected app doesn't send the setting changed broadcast.
|
||||
mInjector.reloadStatusMessages();
|
||||
}
|
||||
|
||||
/** @OnLifecycleEvent(ON_RESUME) */
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
public void onResume() {
|
||||
if (mInjectedSettingsReceiver == null) {
|
||||
mInjectedSettingsReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "Received settings change intent: " + intent);
|
||||
}
|
||||
mInjector.reloadStatusMessages();
|
||||
}
|
||||
};
|
||||
}
|
||||
mContext.registerReceiver(
|
||||
mInjectedSettingsReceiver, INTENT_FILTER_INJECTED_SETTING_CHANGED);
|
||||
}
|
||||
|
||||
/** @OnLifecycleEvent(ON_PAUSE) */
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
||||
public void onPause() {
|
||||
mContext.unregisterReceiver(mInjectedSettingsReceiver);
|
||||
}
|
||||
|
||||
protected Map<Integer, List<Preference>> getLocationServices() {
|
||||
// If location access is locked down by device policy then we only show injected settings
|
||||
// for the primary profile.
|
||||
final int profileUserId = Utils.getManagedProfileId(mUserManager, UserHandle.myUserId());
|
||||
|
||||
return mInjector.getInjectedSettings(mFragment.getPreferenceManager().getContext(),
|
||||
(profileUserId != UserHandle.USER_NULL
|
||||
&& mLocationEnabler.getShareLocationEnforcedAdmin(profileUserId) != null)
|
||||
? UserHandle.myUserId() : UserHandle.USER_CURRENT);
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,8 @@ import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.widget.RestrictedAppPreference;
|
||||
|
||||
@@ -30,7 +32,7 @@ import java.util.Map;
|
||||
* Retrieve the Location Services used in work profile user.
|
||||
*/
|
||||
public class LocationInjectedServicesForWorkPreferenceController extends
|
||||
LocationInjectedServicesPreferenceController {
|
||||
LocationInjectedServiceBasePreferenceController {
|
||||
private static final String TAG = "LocationWorkPrefCtrl";
|
||||
|
||||
public LocationInjectedServicesForWorkPreferenceController(Context context, String key) {
|
||||
@@ -38,10 +40,10 @@ public class LocationInjectedServicesForWorkPreferenceController extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
mCategoryLocationServices.removeAll();
|
||||
protected void injectLocationServices(PreferenceScreen screen) {
|
||||
final PreferenceCategory categoryLocationServices =
|
||||
screen.findPreference(getPreferenceKey());
|
||||
final Map<Integer, List<Preference>> prefs = getLocationServices();
|
||||
boolean show = false;
|
||||
for (Map.Entry<Integer, List<Preference>> entry : prefs.entrySet()) {
|
||||
for (Preference pref : entry.getValue()) {
|
||||
if (pref instanceof RestrictedAppPreference) {
|
||||
@@ -49,11 +51,8 @@ public class LocationInjectedServicesForWorkPreferenceController extends
|
||||
}
|
||||
}
|
||||
if (entry.getKey() != UserHandle.myUserId()) {
|
||||
LocationSettings.addPreferencesSorted(entry.getValue(),
|
||||
mCategoryLocationServices);
|
||||
show = true;
|
||||
LocationSettings.addPreferencesSorted(entry.getValue(), categoryLocationServices);
|
||||
}
|
||||
}
|
||||
mCategoryLocationServices.setVisible(show);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,25 +15,14 @@
|
||||
*/
|
||||
package com.android.settings.location;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.location.SettingInjectorService;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.widget.RestrictedAppPreference;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnPause;
|
||||
import com.android.settingslib.core.lifecycle.events.OnResume;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -41,42 +30,20 @@ import java.util.Map;
|
||||
/**
|
||||
* Preference controller for the injected Location Services.
|
||||
*/
|
||||
public class LocationInjectedServicesPreferenceController extends LocationBasePreferenceController
|
||||
implements LifecycleObserver, OnResume, OnPause {
|
||||
public class LocationInjectedServicesPreferenceController
|
||||
extends LocationInjectedServiceBasePreferenceController {
|
||||
|
||||
private static final String TAG = "LocationPrefCtrl";
|
||||
@VisibleForTesting
|
||||
static final IntentFilter INTENT_FILTER_INJECTED_SETTING_CHANGED =
|
||||
new IntentFilter(SettingInjectorService.ACTION_INJECTED_SETTING_CHANGED);
|
||||
|
||||
protected PreferenceCategory mCategoryLocationServices;
|
||||
@VisibleForTesting
|
||||
AppSettingsInjector mInjector;
|
||||
/** Receives UPDATE_INTENT */
|
||||
@VisibleForTesting
|
||||
BroadcastReceiver mInjectedSettingsReceiver;
|
||||
|
||||
public LocationInjectedServicesPreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(DashboardFragment fragment) {
|
||||
super.init(fragment);
|
||||
mInjector = new AppSettingsInjector(mContext, getMetricsCategory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mCategoryLocationServices = screen.findPreference(getPreferenceKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
mCategoryLocationServices.removeAll();
|
||||
protected void injectLocationServices(PreferenceScreen screen) {
|
||||
final PreferenceCategory categoryLocationServices =
|
||||
screen.findPreference(getPreferenceKey());
|
||||
final Map<Integer, List<Preference>> prefs = getLocationServices();
|
||||
boolean show = false;
|
||||
for (Map.Entry<Integer, List<Preference>> entry : prefs.entrySet()) {
|
||||
for (Preference pref : entry.getValue()) {
|
||||
if (pref instanceof RestrictedAppPreference) {
|
||||
@@ -84,53 +51,11 @@ public class LocationInjectedServicesPreferenceController extends LocationBasePr
|
||||
}
|
||||
}
|
||||
if (entry.getKey() == UserHandle.myUserId()) {
|
||||
if (mCategoryLocationServices != null) {
|
||||
if (categoryLocationServices != null) {
|
||||
LocationSettings.addPreferencesSorted(entry.getValue(),
|
||||
mCategoryLocationServices);
|
||||
categoryLocationServices);
|
||||
}
|
||||
show = true;
|
||||
}
|
||||
}
|
||||
mCategoryLocationServices.setVisible(show);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationModeChanged(int mode, boolean restricted) {
|
||||
// As a safety measure, also reloads on location mode change to ensure the settings are
|
||||
// up-to-date even if an affected app doesn't send the setting changed broadcast.
|
||||
mInjector.reloadStatusMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
if (mInjectedSettingsReceiver == null) {
|
||||
mInjectedSettingsReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "Received settings change intent: " + intent);
|
||||
}
|
||||
mInjector.reloadStatusMessages();
|
||||
}
|
||||
};
|
||||
}
|
||||
mContext.registerReceiver(
|
||||
mInjectedSettingsReceiver, INTENT_FILTER_INJECTED_SETTING_CHANGED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
mContext.unregisterReceiver(mInjectedSettingsReceiver);
|
||||
}
|
||||
|
||||
protected Map<Integer, List<Preference>> getLocationServices() {
|
||||
// If location access is locked down by device policy then we only show injected settings
|
||||
// for the primary profile.
|
||||
final int profileUserId = Utils.getManagedProfileId(mUserManager, UserHandle.myUserId());
|
||||
|
||||
return mInjector.getInjectedSettings(mFragment.getPreferenceManager().getContext(),
|
||||
(profileUserId != UserHandle.USER_NULL
|
||||
&& mLocationEnabler.getShareLocationEnforcedAdmin(profileUserId) != null)
|
||||
? UserHandle.myUserId() : UserHandle.USER_CURRENT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.ServiceState;
|
||||
import android.telephony.SignalStrength;
|
||||
@@ -38,6 +39,7 @@ import android.telephony.TelephonyDisplayInfo;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.Html;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.collection.ArrayMap;
|
||||
@@ -55,7 +57,7 @@ import com.android.settings.network.telephony.MobileNetworkActivity;
|
||||
import com.android.settings.network.telephony.MobileNetworkUtils;
|
||||
import com.android.settings.network.telephony.SignalStrengthListener;
|
||||
import com.android.settings.network.telephony.TelephonyDisplayInfoListener;
|
||||
import com.android.settings.widget.GearPreference;
|
||||
import com.android.settings.widget.MutableGearPreference;
|
||||
import com.android.settings.wifi.WifiPickerTrackerHelper;
|
||||
import com.android.settingslib.SignalIcon.MobileIconGroup;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
@@ -115,7 +117,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl
|
||||
// Map of subscription id to Preference
|
||||
private Map<Integer, Preference> mSubscriptionPreferences;
|
||||
private int mStartOrder;
|
||||
private GearPreference mSubsGearPref;
|
||||
private MutableGearPreference mSubsGearPref;
|
||||
private Config mConfig = null;
|
||||
private SubsPrefCtrlInjector mSubsPrefCtrlInjector;
|
||||
private TelephonyDisplayInfo mTelephonyDisplayInfo =
|
||||
@@ -196,6 +198,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl
|
||||
mSignalStrengthListener.pause();
|
||||
mTelephonyDisplayInfoListener.pause();
|
||||
unRegisterReceiver();
|
||||
resetProviderPreferenceSummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -238,15 +241,20 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl
|
||||
}
|
||||
if (mSubsGearPref == null) {
|
||||
mPreferenceGroup.removeAll();
|
||||
mSubsGearPref = new GearPreference(mContext, null);
|
||||
mSubsGearPref = new MutableGearPreference(mContext, null);
|
||||
mSubsGearPref.setOnPreferenceClickListener(preference -> {
|
||||
connectCarrierNetwork();
|
||||
return true;
|
||||
});
|
||||
|
||||
mSubsGearPref.setOnGearClickListener(p ->
|
||||
startMobileNetworkActivity(mContext, subInfo.getSubscriptionId()));
|
||||
}
|
||||
|
||||
if (!(mContext.getSystemService(UserManager.class)).isAdminUser()) {
|
||||
mSubsGearPref.setGearEnabled(false);
|
||||
}
|
||||
|
||||
mSubsGearPref.setTitle(SubscriptionUtil.getUniqueSubscriptionDisplayName(
|
||||
subInfo, mContext));
|
||||
mSubsGearPref.setOrder(mStartOrder);
|
||||
@@ -275,6 +283,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl
|
||||
String result = mSubsPrefCtrlInjector.getNetworkType(
|
||||
mContext, mConfig, mTelephonyDisplayInfo, subId, isActiveCarrierNetwork);
|
||||
if (mSubsPrefCtrlInjector.isActiveCellularNetwork(mContext) || isActiveCarrierNetwork) {
|
||||
Log.i(TAG, "Active cellular network or active carrier network.");
|
||||
result = mContext.getString(R.string.preference_summary_default_combination,
|
||||
mContext.getString(R.string.mobile_data_connection_active), result);
|
||||
} else if (!isDataInService) {
|
||||
@@ -316,6 +325,13 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl
|
||||
return icon;
|
||||
}
|
||||
|
||||
private void resetProviderPreferenceSummary() {
|
||||
if (mSubsGearPref == null) {
|
||||
return;
|
||||
}
|
||||
mSubsGearPref.setSummary("");
|
||||
}
|
||||
|
||||
private void updateForBase() {
|
||||
final Map<Integer, Preference> existingPrefs = mSubscriptionPreferences;
|
||||
mSubscriptionPreferences = new ArrayMap<>();
|
||||
|
||||
@@ -30,12 +30,14 @@ import android.util.Log;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SidecarFragment;
|
||||
import com.android.settings.core.SettingsBaseActivity;
|
||||
import com.android.settings.network.EnableMultiSimSidecar;
|
||||
import com.android.settings.network.SubscriptionUtil;
|
||||
import com.android.settings.network.SwitchToEuiccSubscriptionSidecar;
|
||||
import com.android.settings.network.SwitchToRemovableSlotSidecar;
|
||||
import com.android.settings.network.UiccSlotUtil;
|
||||
import com.android.settings.sim.SimActivationNotifier;
|
||||
import com.android.settingslib.transition.SettingsTransitionHelper;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
@@ -68,6 +70,9 @@ public class ToggleSubscriptionDialogActivity extends SubscriptionActionDialogAc
|
||||
Intent intent = new Intent(context, ToggleSubscriptionDialogActivity.class);
|
||||
intent.putExtra(ARG_SUB_ID, subId);
|
||||
intent.putExtra(ARG_enable, enable);
|
||||
// suppress page transition as this is a dialog
|
||||
intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
|
||||
SettingsTransitionHelper.TransitionType.TRANSITION_NONE);
|
||||
return intent;
|
||||
}
|
||||
|
||||
|
||||
@@ -141,9 +141,9 @@ public class RecentConversationsPreferenceController extends AbstractPreferenceC
|
||||
int order = 100;
|
||||
boolean hasClearable = false;
|
||||
for (ConversationChannel conversation : conversations) {
|
||||
if (conversation.getParentNotificationChannel().getImportance() == IMPORTANCE_NONE
|
||||
|| (conversation.getParentNotificationChannelGroup() != null
|
||||
&& conversation.getParentNotificationChannelGroup().isBlocked())) {
|
||||
if (conversation.getNotificationChannel().getImportance() == IMPORTANCE_NONE
|
||||
|| (conversation.getNotificationChannelGroup() != null
|
||||
&& conversation.getNotificationChannelGroup().isBlocked())) {
|
||||
continue;
|
||||
}
|
||||
RecentConversationPreference pref =
|
||||
@@ -179,12 +179,12 @@ public class RecentConversationsPreferenceController extends AbstractPreferenceC
|
||||
pref.setSummary(getSummary(conversation));
|
||||
pref.setIcon(mBackend.getConversationDrawable(mContext, conversation.getShortcutInfo(),
|
||||
pkg, uid, false));
|
||||
pref.setKey(conversation.getParentNotificationChannel().getId()
|
||||
pref.setKey(conversation.getNotificationChannel().getId()
|
||||
+ ":" + conversationId);
|
||||
pref.setOnPreferenceClickListener(preference -> {
|
||||
mBackend.createConversationNotificationChannel(
|
||||
pkg, uid,
|
||||
conversation.getParentNotificationChannel(),
|
||||
conversation.getNotificationChannel(),
|
||||
conversationId);
|
||||
getSubSettingLauncher(conversation, pref.getTitle()).launch();
|
||||
return true;
|
||||
@@ -194,11 +194,11 @@ public class RecentConversationsPreferenceController extends AbstractPreferenceC
|
||||
}
|
||||
|
||||
CharSequence getSummary(ConversationChannel conversation) {
|
||||
return conversation.getParentNotificationChannelGroup() == null
|
||||
? conversation.getParentNotificationChannel().getName()
|
||||
return conversation.getNotificationChannelGroup() == null
|
||||
? conversation.getNotificationChannel().getName()
|
||||
: mContext.getString(R.string.notification_conversation_summary,
|
||||
conversation.getParentNotificationChannel().getName(),
|
||||
conversation.getParentNotificationChannelGroup().getName());
|
||||
conversation.getNotificationChannel().getName(),
|
||||
conversation.getNotificationChannelGroup().getName());
|
||||
}
|
||||
|
||||
CharSequence getTitle(ConversationChannel conversation) {
|
||||
@@ -213,7 +213,7 @@ public class RecentConversationsPreferenceController extends AbstractPreferenceC
|
||||
channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME,
|
||||
conversation.getShortcutInfo().getPackage());
|
||||
channelArgs.putString(Settings.EXTRA_CHANNEL_ID,
|
||||
conversation.getParentNotificationChannel().getId());
|
||||
conversation.getNotificationChannel().getId());
|
||||
channelArgs.putString(Settings.EXTRA_CONVERSATION_ID,
|
||||
conversation.getShortcutInfo().getId());
|
||||
|
||||
@@ -235,8 +235,8 @@ public class RecentConversationsPreferenceController extends AbstractPreferenceC
|
||||
o2.getShortcutInfo().getLabel());
|
||||
|
||||
if (labelComparison == 0) {
|
||||
return o1.getParentNotificationChannel().getId().compareTo(
|
||||
o2.getParentNotificationChannel().getId());
|
||||
return o1.getNotificationChannel().getId().compareTo(
|
||||
o2.getNotificationChannel().getId());
|
||||
}
|
||||
|
||||
return labelComparison;
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.security.AppUriAuthenticationPolicy;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -85,11 +86,13 @@ public class CredentialManagementAppAdapter extends RecyclerView.Adapter<Recycle
|
||||
ApplicationInfo applicationInfo =
|
||||
mPackageManager.getApplicationInfo(mCredentialManagerPackage, 0);
|
||||
mAppIconView.setImageDrawable(mPackageManager.getApplicationIcon(applicationInfo));
|
||||
mTitleView.setText(mContext.getString(R.string.request_manage_credentials_title,
|
||||
mTitleView.setText(TextUtils.expandTemplate(
|
||||
mContext.getText(R.string.request_manage_credentials_title),
|
||||
applicationInfo.loadLabel(mPackageManager)));
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
mAppIconView.setImageDrawable(null);
|
||||
mTitleView.setText(mContext.getString(R.string.request_manage_credentials_title,
|
||||
mTitleView.setText(TextUtils.expandTemplate(
|
||||
mContext.getText(R.string.request_manage_credentials_title),
|
||||
mCredentialManagerPackage));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,12 +80,29 @@ public class CredentialManagementAppButtonsController extends BasePreferenceCont
|
||||
private void displayButtons(PreferenceScreen screen) {
|
||||
if (mHasCredentialManagerPackage) {
|
||||
((ActionButtonsPreference) screen.findPreference(getPreferenceKey()))
|
||||
.setButton1Text(R.string.remove_credential_management_app)
|
||||
.setButton1Icon(R.drawable.ic_undo_24)
|
||||
.setButton1OnClickListener(view -> removeCredentialManagementApp());
|
||||
.setButton1Text(R.string.uninstall_certs_credential_management_app)
|
||||
.setButton1Icon(R.drawable.ic_upload)
|
||||
.setButton1OnClickListener(view -> uninstallCertificates())
|
||||
.setButton2Text(R.string.remove_credential_management_app)
|
||||
.setButton2Icon(R.drawable.ic_delete)
|
||||
.setButton2OnClickListener(view -> removeCredentialManagementApp());
|
||||
}
|
||||
}
|
||||
|
||||
private void uninstallCertificates() {
|
||||
mExecutor.execute(() -> {
|
||||
try {
|
||||
IKeyChainService service = KeyChain.bind(mContext).getService();
|
||||
for (String existingAlias :
|
||||
service.getCredentialManagementAppPolicy().getAliases()) {
|
||||
service.removeKeyPair(existingAlias);
|
||||
}
|
||||
} catch (InterruptedException | RemoteException e) {
|
||||
Log.e(TAG, "Unable to uninstall certificates");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void removeCredentialManagementApp() {
|
||||
mExecutor.execute(() -> {
|
||||
try {
|
||||
|
||||
@@ -83,7 +83,6 @@ public class CredentialManagementAppHeaderController extends BasePreferenceContr
|
||||
TextView titleView = headerPref.findViewById(R.id.entity_header_title);
|
||||
TextView summary1 = headerPref.findViewById(R.id.entity_header_summary);
|
||||
TextView summary2 = headerPref.findViewById(R.id.entity_header_second_summary);
|
||||
summary1.setVisibility(View.GONE);
|
||||
summary2.setVisibility(View.GONE);
|
||||
|
||||
try {
|
||||
@@ -91,6 +90,7 @@ public class CredentialManagementAppHeaderController extends BasePreferenceContr
|
||||
mPackageManager.getApplicationInfo(mCredentialManagerPackageName, 0);
|
||||
appIconView.setImageDrawable(mPackageManager.getApplicationIcon(applicationInfo));
|
||||
titleView.setText(applicationInfo.loadLabel(mPackageManager));
|
||||
summary1.setText(R.string.certificate_management_app_description);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
appIconView.setImageDrawable(null);
|
||||
titleView.setText(mCredentialManagerPackageName);
|
||||
|
||||
@@ -21,7 +21,10 @@ import android.app.Activity;
|
||||
import android.app.admin.DevicePolicyEventLogger;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -37,7 +40,9 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
@@ -83,6 +88,7 @@ public class RequestManageCredentials extends Activity {
|
||||
private KeyChain.KeyChainConnection mKeyChainConnection;
|
||||
|
||||
private boolean mDisplayingButtonPanel = false;
|
||||
private boolean mIsLandscapeMode = false;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
@@ -114,6 +120,8 @@ public class RequestManageCredentials extends Activity {
|
||||
.setStrings(mCredentialManagerPackage)
|
||||
.write();
|
||||
setContentView(R.layout.request_manage_credentials);
|
||||
mIsLandscapeMode = getResources().getConfiguration().orientation
|
||||
== Configuration.ORIENTATION_LANDSCAPE;
|
||||
|
||||
mKeyChainTread = new HandlerThread("KeyChainConnection");
|
||||
mKeyChainTread.start();
|
||||
@@ -134,6 +142,9 @@ public class RequestManageCredentials extends Activity {
|
||||
getNumberOfAuthenticationPolicyUris(mAuthenticationPolicy))
|
||||
.write();
|
||||
|
||||
if (mIsLandscapeMode) {
|
||||
loadHeader();
|
||||
}
|
||||
loadRecyclerView();
|
||||
loadButtons();
|
||||
loadExtendedFloatingActionButton();
|
||||
@@ -193,7 +204,7 @@ public class RequestManageCredentials extends Activity {
|
||||
|
||||
CredentialManagementAppAdapter recyclerViewAdapter = new CredentialManagementAppAdapter(
|
||||
this, mCredentialManagerPackage, mAuthenticationPolicy.getAppAndUriMappings(),
|
||||
/* include header= */ true, /* include expander= */ false);
|
||||
/* include header= */ !mIsLandscapeMode, /* include expander= */ false);
|
||||
mRecyclerView.setAdapter(recyclerViewAdapter);
|
||||
}
|
||||
|
||||
@@ -214,12 +225,33 @@ public class RequestManageCredentials extends Activity {
|
||||
private void loadExtendedFloatingActionButton() {
|
||||
mExtendedFab = findViewById(R.id.extended_fab);
|
||||
mExtendedFab.setOnClickListener(v -> {
|
||||
mRecyclerView.scrollToPosition(mAuthenticationPolicy.getAppAndUriMappings().size());
|
||||
final int position = mIsLandscapeMode
|
||||
? mAuthenticationPolicy.getAppAndUriMappings().size() - 1
|
||||
: mAuthenticationPolicy.getAppAndUriMappings().size();
|
||||
mRecyclerView.scrollToPosition(position);
|
||||
mExtendedFab.hide();
|
||||
showButtonPanel();
|
||||
});
|
||||
}
|
||||
|
||||
private void loadHeader() {
|
||||
final ImageView mAppIconView = findViewById(R.id.credential_management_app_icon);
|
||||
final TextView mTitleView = findViewById(R.id.credential_management_app_title);
|
||||
try {
|
||||
ApplicationInfo applicationInfo =
|
||||
getPackageManager().getApplicationInfo(mCredentialManagerPackage, 0);
|
||||
mAppIconView.setImageDrawable(getPackageManager().getApplicationIcon(applicationInfo));
|
||||
mTitleView.setText(TextUtils.expandTemplate(
|
||||
getText(R.string.request_manage_credentials_title),
|
||||
applicationInfo.loadLabel(getPackageManager())));
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
mAppIconView.setImageDrawable(null);
|
||||
mTitleView.setText(TextUtils.expandTemplate(
|
||||
getText(R.string.request_manage_credentials_title),
|
||||
mCredentialManagerPackage));
|
||||
}
|
||||
}
|
||||
|
||||
private void setOrUpdateCredentialManagementAppAndFinish() {
|
||||
try {
|
||||
mKeyChainConnection.getService().setCredentialManagementApp(
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.google.android.material.card.MaterialCardView;
|
||||
* Preference that wrapped by {@link MaterialCardView}, only support to set icon, title and summary
|
||||
*/
|
||||
public class CardPreference extends Preference {
|
||||
|
||||
public CardPreference(Context context) {
|
||||
this(context, null /* attrs */);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ import com.android.settingslib.RestrictedPreference;
|
||||
* A preference with a Gear on the side
|
||||
*/
|
||||
public class GearPreference extends RestrictedPreference implements View.OnClickListener {
|
||||
|
||||
// Default true for gear available even if the preference itself is disabled.
|
||||
protected boolean mGearState = true;
|
||||
private OnGearClickListener mOnGearClickListener;
|
||||
|
||||
public GearPreference(Context context, AttributeSet attrs) {
|
||||
@@ -41,6 +42,16 @@ public class GearPreference extends RestrictedPreference implements View.OnClick
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
/** Sets state of gear button. */
|
||||
public void setGearEnabled(boolean enabled) {
|
||||
mGearState = enabled;
|
||||
}
|
||||
|
||||
/** Gets state of gear button. */
|
||||
public boolean isGearEnabled() {
|
||||
return mGearState;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getSecondTargetResId() {
|
||||
return R.layout.preference_widget_gear;
|
||||
@@ -62,7 +73,8 @@ public class GearPreference extends RestrictedPreference implements View.OnClick
|
||||
gear.setVisibility(View.GONE);
|
||||
gear.setOnClickListener(null);
|
||||
}
|
||||
gear.setEnabled(true); // Make gear available even if the preference itself is disabled.
|
||||
// Make gear available even if the preference itself is disabled.
|
||||
gear.setEnabled(mGearState);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
57
src/com/android/settings/widget/MutableGearPreference.java
Normal file
57
src/com/android/settings/widget/MutableGearPreference.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.utils.ColorUtil;
|
||||
|
||||
/** A preference with a Gear on the side and mutable Gear color. */
|
||||
public class MutableGearPreference extends GearPreference {
|
||||
private static final int VALUE_ENABLED_ALPHA = 255;
|
||||
|
||||
private ImageView mGear;
|
||||
private Context mContext;
|
||||
private int mDisabledAlphaValue;
|
||||
|
||||
public MutableGearPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
mDisabledAlphaValue = (int) (ColorUtil.getDisabledAlpha(context) * VALUE_ENABLED_ALPHA);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGearEnabled(boolean enabled) {
|
||||
if (mGear != null) {
|
||||
mGear.setEnabled(enabled);
|
||||
mGear.setImageAlpha(enabled ? VALUE_ENABLED_ALPHA : mDisabledAlphaValue);
|
||||
}
|
||||
mGearState = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
mGear = (ImageView) holder.findViewById(R.id.settings_button);
|
||||
setGearEnabled(mGearState);
|
||||
}
|
||||
}
|
||||
136
tests/robotests/res/layout/main_clear.xml
Normal file
136
tests/robotests/res/layout/main_clear.xml
Normal file
@@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<com.google.android.setupdesign.GlifLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/setup_wizard_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:theme="@style/GlifV3Theme.Footer"
|
||||
android:orientation="vertical"
|
||||
android:icon="@drawable/ic_delete_accent"
|
||||
app:sucHeaderText="@string/main_clear_title">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/main_clear_scrollview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="@dimen/reset_main_clear_margin_start"
|
||||
android:layout_marginEnd="@dimen/reset_main_clear_margin_end">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/main_clear_container"
|
||||
style="@style/SudContentFrame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:id="@+id/sud_layout_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_clear_desc"/>
|
||||
<TextView
|
||||
android:id="@+id/also_erases_external"
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:text="@string/main_clear_desc_also_erases_external"/>
|
||||
<TextView
|
||||
android:id="@+id/also_erases_esim"
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:text="@string/main_clear_desc_also_erases_esim"/>
|
||||
<TextView
|
||||
android:id="@+id/accounts_label"
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:text="@string/main_clear_accounts"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/accounts"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
<!-- Do not add any children here as they will be removed in the MainClear.java
|
||||
code. A list of accounts will be inserted programmatically. -->
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/other_users_present"
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:text="@string/main_clear_other_users_present"/>
|
||||
<TextView
|
||||
android:id="@+id/no_cancel_mobile_plan"
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:text="@string/main_clear_desc_no_cancel_mobile_plan"/>
|
||||
<TextView
|
||||
android:id="@+id/erase_external_option_text"
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_clear_desc_erase_external_storage"/>
|
||||
<LinearLayout
|
||||
android:id="@+id/erase_external_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:focusable="true"
|
||||
android:clickable="true">
|
||||
<CheckBox
|
||||
android:id="@+id/erase_external"
|
||||
style="@style/SudCheckBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:focusable="false"
|
||||
android:clickable="false"
|
||||
android:duplicateParentState="true"/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
style="@style/TextAppearance.SudGlifItemTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/erase_external_storage"/>
|
||||
<TextView
|
||||
style="@style/TextAppearance.SudGlifItemSummary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/erase_external_storage_description"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/reset_esim_checkbox"/>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</com.google.android.setupdesign.GlifLayout>
|
||||
40
tests/robotests/res/layout/main_clear_confirm.xml
Normal file
40
tests/robotests/res/layout/main_clear_confirm.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
<com.google.android.setupdesign.GlifLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:theme="@style/SudThemeGlifV3.DayNight"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/setup_wizard_layout"
|
||||
android:icon="@drawable/ic_delete_accent"
|
||||
app:sucHeaderText="@string/main_clear_confirm_title">
|
||||
|
||||
<LinearLayout
|
||||
style="@style/SudContentFrame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sud_layout_description"
|
||||
style="@style/SudItemTitle.GlifDescription"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/main_clear_final_desc"/>
|
||||
</LinearLayout>
|
||||
</com.google.android.setupdesign.GlifLayout>
|
||||
@@ -20,11 +20,10 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.content.PermissionChecker;
|
||||
import android.content.pm.CrossProfileApps;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PermissionInfo;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.UserManager;
|
||||
|
||||
@@ -37,19 +36,18 @@ import com.google.common.collect.ImmutableList;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.shadows.ShadowPermissionChecker;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class InteractAcrossProfilesDetailsTest {
|
||||
|
||||
private static final int PERSONAL_PROFILE_ID = 0;
|
||||
private static final int WORK_PROFILE_ID = 10;
|
||||
private static final int PACKAGE_UID = 0;
|
||||
private static final String CROSS_PROFILE_PACKAGE_NAME = "crossProfilePackage";
|
||||
public static final String INTERACT_ACROSS_PROFILES_PERMISSION =
|
||||
"android.permission.INTERACT_ACROSS_PROFILES";
|
||||
|
||||
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private final AppOpsManager mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
|
||||
private final PackageManager mPackageManager = mContext.getPackageManager();
|
||||
private final UserManager mUserManager = mContext.getSystemService(UserManager.class);
|
||||
private final CrossProfileApps mCrossProfileApps = mContext.getSystemService(
|
||||
@@ -68,10 +66,10 @@ public class InteractAcrossProfilesDetailsTest {
|
||||
WORK_PROFILE_ID, ImmutableList.of(CROSS_PROFILE_PACKAGE_NAME));
|
||||
shadowOf(mCrossProfileApps).addCrossProfilePackage(
|
||||
CROSS_PROFILE_PACKAGE_NAME);
|
||||
String appOp = AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION);
|
||||
shadowOf(mAppOpsManager).setMode(
|
||||
appOp, PACKAGE_UID, CROSS_PROFILE_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
|
||||
shadowOf(mPackageManager).addPermissionInfo(createCrossProfilesPermissionInfo());
|
||||
ShadowPermissionChecker.setResult(
|
||||
CROSS_PROFILE_PACKAGE_NAME,
|
||||
INTERACT_ACROSS_PROFILES_PERMISSION,
|
||||
PermissionChecker.PERMISSION_GRANTED);
|
||||
|
||||
assertThat(InteractAcrossProfilesDetails.getPreferenceSummary(
|
||||
mContext, CROSS_PROFILE_PACKAGE_NAME))
|
||||
@@ -91,11 +89,10 @@ public class InteractAcrossProfilesDetailsTest {
|
||||
WORK_PROFILE_ID, ImmutableList.of(CROSS_PROFILE_PACKAGE_NAME));
|
||||
shadowOf(mCrossProfileApps).addCrossProfilePackage(
|
||||
CROSS_PROFILE_PACKAGE_NAME);
|
||||
String appOp = AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION);
|
||||
shadowOf(mAppOpsManager).setMode(
|
||||
appOp, PACKAGE_UID, CROSS_PROFILE_PACKAGE_NAME, AppOpsManager.MODE_IGNORED);
|
||||
shadowOf(mPackageManager).addPermissionInfo(createCrossProfilesPermissionInfo());
|
||||
|
||||
ShadowPermissionChecker.setResult(
|
||||
CROSS_PROFILE_PACKAGE_NAME,
|
||||
INTERACT_ACROSS_PROFILES_PERMISSION,
|
||||
PermissionChecker.PERMISSION_SOFT_DENIED);
|
||||
assertThat(InteractAcrossProfilesDetails.getPreferenceSummary(
|
||||
mContext, CROSS_PROFILE_PACKAGE_NAME))
|
||||
.isEqualTo(mContext.getString(
|
||||
@@ -114,11 +111,4 @@ public class InteractAcrossProfilesDetailsTest {
|
||||
.isEqualTo(mContext.getString(
|
||||
R.string.interact_across_profiles_summary_not_allowed));
|
||||
}
|
||||
|
||||
private PermissionInfo createCrossProfilesPermissionInfo() {
|
||||
PermissionInfo permissionInfo = new PermissionInfo();
|
||||
permissionInfo.name = INTERACT_ACROSS_PROFILES_PERMISSION;
|
||||
permissionInfo.protectionLevel = PermissionInfo.PROTECTION_FLAG_APPOP;
|
||||
return permissionInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.Context;
|
||||
import android.content.PermissionChecker;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
@@ -51,7 +50,6 @@ public class InteractAcrossProfilesSettingsTest {
|
||||
private static final int PERSONAL_PROFILE_ID = 0;
|
||||
private static final int WORK_PROFILE_ID = 10;
|
||||
private static final int WORK_UID = UserHandle.PER_USER_RANGE * WORK_PROFILE_ID;
|
||||
private static final int PACKAGE_UID = 0;
|
||||
|
||||
private static final String PERSONAL_CROSS_PROFILE_PACKAGE = "personalCrossProfilePackage";
|
||||
private static final String PERSONAL_NON_CROSS_PROFILE_PACKAGE =
|
||||
@@ -71,7 +69,6 @@ public class InteractAcrossProfilesSettingsTest {
|
||||
private final UserManager mUserManager = mContext.getSystemService(UserManager.class);
|
||||
private final CrossProfileApps mCrossProfileApps =
|
||||
mContext.getSystemService(CrossProfileApps.class);
|
||||
private final AppOpsManager mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
|
||||
|
||||
@Test
|
||||
public void collectConfigurableApps_fromPersonal_returnsCombinedPackages() {
|
||||
@@ -84,8 +81,8 @@ public class InteractAcrossProfilesSettingsTest {
|
||||
PERSONAL_PROFILE_ID, PERSONAL_PROFILE_INSTALLED_PACKAGES);
|
||||
shadowOf(mPackageManager).setInstalledPackagesForUserId(
|
||||
WORK_PROFILE_ID, WORK_PROFILE_INSTALLED_PACKAGES);
|
||||
installCrossProfilePackage(PERSONAL_PROFILE_ID, PERSONAL_CROSS_PROFILE_PACKAGE);
|
||||
installCrossProfilePackage(WORK_PROFILE_ID, WORK_CROSS_PROFILE_PACKAGE);
|
||||
installCrossProfilePackage(PERSONAL_CROSS_PROFILE_PACKAGE);
|
||||
installCrossProfilePackage(WORK_CROSS_PROFILE_PACKAGE);
|
||||
|
||||
List<Pair<ApplicationInfo, UserHandle>> apps =
|
||||
InteractAcrossProfilesSettings.collectConfigurableApps(
|
||||
@@ -110,8 +107,8 @@ public class InteractAcrossProfilesSettingsTest {
|
||||
PERSONAL_PROFILE_ID, PERSONAL_PROFILE_INSTALLED_PACKAGES);
|
||||
shadowOf(mPackageManager).setInstalledPackagesForUserId(
|
||||
WORK_PROFILE_ID, WORK_PROFILE_INSTALLED_PACKAGES);
|
||||
installCrossProfilePackage(PERSONAL_PROFILE_ID, PERSONAL_CROSS_PROFILE_PACKAGE);
|
||||
installCrossProfilePackage(WORK_PROFILE_ID, WORK_CROSS_PROFILE_PACKAGE);
|
||||
installCrossProfilePackage(PERSONAL_CROSS_PROFILE_PACKAGE);
|
||||
installCrossProfilePackage(WORK_CROSS_PROFILE_PACKAGE);
|
||||
|
||||
List<Pair<ApplicationInfo, UserHandle>> apps =
|
||||
InteractAcrossProfilesSettings.collectConfigurableApps(
|
||||
@@ -130,7 +127,7 @@ public class InteractAcrossProfilesSettingsTest {
|
||||
PERSONAL_PROFILE_ID, "personal-profile"/* name */, 0/* flags */);
|
||||
shadowOf(mPackageManager).setInstalledPackagesForUserId(
|
||||
PERSONAL_PROFILE_ID, PERSONAL_PROFILE_INSTALLED_PACKAGES);
|
||||
installCrossProfilePackage(PERSONAL_PROFILE_ID, PERSONAL_CROSS_PROFILE_PACKAGE);
|
||||
installCrossProfilePackage(PERSONAL_CROSS_PROFILE_PACKAGE);
|
||||
|
||||
List<Pair<ApplicationInfo, UserHandle>> apps =
|
||||
InteractAcrossProfilesSettings.collectConfigurableApps(
|
||||
@@ -150,10 +147,9 @@ public class InteractAcrossProfilesSettingsTest {
|
||||
PERSONAL_PROFILE_ID, PERSONAL_PROFILE_INSTALLED_PACKAGES);
|
||||
shadowOf(mPackageManager).setInstalledPackagesForUserId(
|
||||
WORK_PROFILE_ID, WORK_PROFILE_INSTALLED_PACKAGES);
|
||||
installCrossProfilePackage(PERSONAL_PROFILE_ID, PERSONAL_CROSS_PROFILE_PACKAGE);
|
||||
installCrossProfilePackage(WORK_PROFILE_ID, WORK_CROSS_PROFILE_PACKAGE);
|
||||
installCrossProfilePackage(PERSONAL_CROSS_PROFILE_PACKAGE);
|
||||
installCrossProfilePackage(WORK_CROSS_PROFILE_PACKAGE);
|
||||
shadowOf(mCrossProfileApps).addCrossProfilePackage(PERSONAL_CROSS_PROFILE_PACKAGE);
|
||||
String appOp = AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION);
|
||||
ShadowPermissionChecker.setResult(
|
||||
PERSONAL_CROSS_PROFILE_PACKAGE,
|
||||
INTERACT_ACROSS_PROFILES_PERMISSION,
|
||||
@@ -169,7 +165,7 @@ public class InteractAcrossProfilesSettingsTest {
|
||||
assertThat(numOfApps).isEqualTo(1);
|
||||
}
|
||||
|
||||
private void installCrossProfilePackage(int profileId, String packageName) {
|
||||
private void installCrossProfilePackage(String packageName) {
|
||||
PackageInfo personalPackageInfo = shadowOf(mPackageManager).getInternalMutablePackageInfo(
|
||||
packageName);
|
||||
personalPackageInfo.requestedPermissions = new String[]{
|
||||
|
||||
@@ -20,46 +20,65 @@ import static android.provider.Settings.Secure.CAMERA_AUTOROTATE;
|
||||
|
||||
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.anyString;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.ResolveInfoBuilder;
|
||||
import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = ShadowSensorPrivacyManager.class)
|
||||
public class SmartAutoRotatePreferenceControllerTest {
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private Context mContext;
|
||||
private static final String PACKAGE_NAME = "package_name";
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
private Resources mResources;
|
||||
private Context mContext;
|
||||
private ContentResolver mContentResolver;
|
||||
private SmartAutoRotatePreferenceController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = Mockito.spy(RuntimeEnvironment.application);
|
||||
FakeFeatureFactory.setupForTest();
|
||||
mContentResolver = RuntimeEnvironment.application.getContentResolver();
|
||||
|
||||
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
when(mContext.getContentResolver()).thenReturn(mContentResolver);
|
||||
|
||||
doReturn(PACKAGE_NAME).when(mPackageManager).getRotationResolverPackageName();
|
||||
doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission(
|
||||
Manifest.permission.CAMERA, PACKAGE_NAME);
|
||||
when(mContext.getString(R.string.auto_rotate_option_off))
|
||||
.thenReturn("Off");
|
||||
when(mContext.getString(R.string.auto_rotate_option_on))
|
||||
@@ -68,8 +87,14 @@ public class SmartAutoRotatePreferenceControllerTest {
|
||||
.thenReturn("On - Face-based");
|
||||
|
||||
disableCameraBasedRotation();
|
||||
final ResolveInfo resolveInfo = new ResolveInfoBuilder(PACKAGE_NAME).build();
|
||||
resolveInfo.serviceInfo = new ServiceInfo();
|
||||
when(mPackageManager.resolveService(any(), anyInt())).thenReturn(resolveInfo);
|
||||
|
||||
mController = new SmartAutoRotatePreferenceController(mContext, "smart_auto_rotate");
|
||||
mController = Mockito.spy(
|
||||
new SmartAutoRotatePreferenceController(mContext, "smart_auto_rotate"));
|
||||
when(mController.isCameraLocked()).thenReturn(false);
|
||||
when(mController.isPowerSaveMode()).thenReturn(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -82,33 +107,37 @@ public class SmartAutoRotatePreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatePreference_settingsIsOff_shouldTurnOffToggle() {
|
||||
public void getSummary_settingsIsOff_returnsOff() {
|
||||
disableAutoRotation();
|
||||
|
||||
assertThat(mController.getSummary()).isEqualTo("Off");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatePreference_settingsIsOn_shouldTurnOnToggle() {
|
||||
public void getSummary_settingsIsOn_returnsOn() {
|
||||
enableAutoRotation();
|
||||
|
||||
assertThat(mController.getSummary()).isEqualTo("On");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatePreference_settingsIsCameraBased_shouldTurnOnToggle() {
|
||||
public void getSummary_autoRotateOffSmartAutoRotateOn_returnsOff() {
|
||||
enableCameraBasedRotation();
|
||||
disableAutoRotation();
|
||||
|
||||
assertThat(mController.getSummary()).isEqualTo("Off");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatePreference_smartAutoRotateOn_returnsFaceBased() {
|
||||
enableCameraBasedRotation();
|
||||
enableAutoRotation();
|
||||
|
||||
assertThat(mController.getSummary()).isEqualTo("On - Face-based");
|
||||
|
||||
disableAutoRotation();
|
||||
|
||||
assertThat(mController.getSummary()).isEqualTo("Off");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatePreference_settingsIsOff_noSmartAuto_shouldTurnOffToggle() {
|
||||
public void getSummary_noSmartAuto_returnsOff() {
|
||||
disableAutoRotation();
|
||||
Settings.Secure.putStringForUser(mContentResolver,
|
||||
CAMERA_AUTOROTATE, null, UserHandle.USER_CURRENT);
|
||||
@@ -118,7 +147,7 @@ public class SmartAutoRotatePreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatePreference_settingsIsOn_noSmartAuto_shouldTurnOnToggle() {
|
||||
public void getSummary_noSmartAuto_returnsOn() {
|
||||
enableAutoRotation();
|
||||
Settings.Secure.putStringForUser(mContentResolver,
|
||||
CAMERA_AUTOROTATE, null, UserHandle.USER_CURRENT);
|
||||
@@ -126,6 +155,34 @@ public class SmartAutoRotatePreferenceControllerTest {
|
||||
assertThat(mController.getSummary()).isEqualTo("On");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSummary_noCameraPermission_returnsOn() {
|
||||
enableAutoRotation();
|
||||
enableCameraBasedRotation();
|
||||
doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
|
||||
Manifest.permission.CAMERA, PACKAGE_NAME);
|
||||
|
||||
assertThat(mController.getSummary()).isEqualTo("On");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSummary_cameraDisabled_returnsOn() {
|
||||
enableAutoRotation();
|
||||
enableCameraBasedRotation();
|
||||
when(mController.isCameraLocked()).thenReturn(true);
|
||||
|
||||
assertThat(mController.getSummary()).isEqualTo("On");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSummary_powerSaveEnabled_returnsOn() {
|
||||
enableAutoRotation();
|
||||
enableCameraBasedRotation();
|
||||
when(mController.isPowerSaveMode()).thenReturn(true);
|
||||
|
||||
assertThat(mController.getSummary()).isEqualTo("On");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAvailabilityStatus() {
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(BasePreferenceController
|
||||
@@ -158,14 +215,14 @@ public class SmartAutoRotatePreferenceControllerTest {
|
||||
|
||||
private void enableAutoRotationPreference() {
|
||||
when(mPackageManager.hasSystemFeature(anyString())).thenReturn(true);
|
||||
when(mContext.getResources().getBoolean(anyInt())).thenReturn(true);
|
||||
when(mResources.getBoolean(anyInt())).thenReturn(true);
|
||||
Settings.System.putInt(mContentResolver,
|
||||
Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0);
|
||||
}
|
||||
|
||||
private void disableAutoRotationPreference() {
|
||||
when(mPackageManager.hasSystemFeature(anyString())).thenReturn(true);
|
||||
when(mContext.getResources().getBoolean(anyInt())).thenReturn(true);
|
||||
when(mResources.getBoolean(anyInt())).thenReturn(true);
|
||||
Settings.System.putInt(mContentResolver,
|
||||
Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 1);
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ public class BatteryEntryTest {
|
||||
when(consumer.getUid()).thenReturn(APP_UID);
|
||||
when(consumer.getPackageWithHighestDrain()).thenReturn(highDrainPackage);
|
||||
return new BatteryEntry(mMockContext, mockHandler, mockUserManager,
|
||||
consumer, false, packages, packageName);
|
||||
consumer, false, APP_UID, packages, packageName);
|
||||
}
|
||||
|
||||
private BatteryEntry createAggregateBatteryEntry(int powerComponentId) {
|
||||
@@ -108,7 +108,7 @@ public class BatteryEntryTest {
|
||||
UserBatteryConsumer consumer = mock(UserBatteryConsumer.class);
|
||||
when(consumer.getUserId()).thenReturn(userId);
|
||||
return new BatteryEntry(mMockContext, mockHandler, mockUserManager,
|
||||
consumer, false, null, null);
|
||||
consumer, false, 0, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -169,12 +169,12 @@ public class BatteryEntryTest {
|
||||
|
||||
@Test
|
||||
public void getTimeInForegroundMs_app() {
|
||||
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
|
||||
mockUserManager, mUidBatteryConsumer, false, null, null);
|
||||
|
||||
when(mUidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND))
|
||||
.thenReturn(100L);
|
||||
|
||||
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
|
||||
mockUserManager, mUidBatteryConsumer, false, 0, null, null);
|
||||
|
||||
assertThat(entry.getTimeInForegroundMs()).isEqualTo(100L);
|
||||
}
|
||||
|
||||
@@ -188,12 +188,12 @@ public class BatteryEntryTest {
|
||||
|
||||
@Test
|
||||
public void getTimeInBackgroundMs_app() {
|
||||
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
|
||||
mockUserManager, mUidBatteryConsumer, false, null, null);
|
||||
|
||||
when(mUidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND))
|
||||
.thenReturn(100L);
|
||||
|
||||
final BatteryEntry entry = new BatteryEntry(RuntimeEnvironment.application, mockHandler,
|
||||
mockUserManager, mUidBatteryConsumer, false, 0, null, null);
|
||||
|
||||
assertThat(entry.getTimeInBackgroundMs()).isEqualTo(100L);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import android.os.UserHandle;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
@@ -316,6 +317,7 @@ public final class ConvertUtilsTest {
|
||||
.isEqualTo(entry.mConsumePower * ratio);
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void testUtcToLocalTime_returnExpectedResult() {
|
||||
ConvertUtils.sZoneId = null;
|
||||
@@ -336,6 +338,7 @@ public final class ConvertUtilsTest {
|
||||
assertThat(ConvertUtils.sLocale).isEqualTo(new Locale("en_US"));
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void testUtcToLocalTimeHour_12HourFormat_returnExpectedResult() {
|
||||
ConvertUtils.sZoneIdForHour = null;
|
||||
@@ -357,6 +360,7 @@ public final class ConvertUtilsTest {
|
||||
assertThat(ConvertUtils.sLocaleForHour).isEqualTo(new Locale("en_US"));
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void testUtcToLocalTimeHour_24HourFormat_returnExpectedResult() {
|
||||
ConvertUtils.sZoneIdForHour = null;
|
||||
|
||||
@@ -67,8 +67,6 @@ public class LocationInjectedServicesPreferenceControllerTest {
|
||||
@Mock
|
||||
private PreferenceCategory mCategoryPrimary;
|
||||
@Mock
|
||||
private PreferenceCategory mCategoryManaged;
|
||||
@Mock
|
||||
private PreferenceScreen mScreen;
|
||||
@Mock
|
||||
private AppSettingsInjector mSettingsInjector;
|
||||
@@ -114,31 +112,6 @@ public class LocationInjectedServicesPreferenceControllerTest {
|
||||
verify(mContext).unregisterReceiver(mController.mInjectedSettingsReceiver);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_shouldRemoveAllAndAddInjectedSettings() {
|
||||
final List<Preference> preferences = new ArrayList<>();
|
||||
final Map<Integer, List<Preference>> map = new ArrayMap<>();
|
||||
final Preference pref1 = new Preference(mContext);
|
||||
pref1.setTitle("Title1");
|
||||
final Preference pref2 = new Preference(mContext);
|
||||
pref2.setTitle("Title2");
|
||||
preferences.add(pref1);
|
||||
preferences.add(pref2);
|
||||
map.put(UserHandle.myUserId(), preferences);
|
||||
doReturn(map)
|
||||
.when(mSettingsInjector).getInjectedSettings(any(Context.class), anyInt());
|
||||
when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext);
|
||||
ShadowUserManager.getShadow().setProfileIdsWithDisabled(new int[]{UserHandle.myUserId()});
|
||||
|
||||
mController.displayPreference(mScreen);
|
||||
|
||||
mController.updateState(mCategoryPrimary);
|
||||
|
||||
verify(mCategoryPrimary).removeAll();
|
||||
verify(mCategoryPrimary).addPreference(pref1);
|
||||
verify(mCategoryPrimary).addPreference(pref2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void workProfileDisallowShareLocationOn_getParentUserLocationServicesOnly() {
|
||||
final int fakeWorkProfileId = 123;
|
||||
@@ -158,7 +131,6 @@ public class LocationInjectedServicesPreferenceControllerTest {
|
||||
when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(componentName);
|
||||
|
||||
mController.displayPreference(mScreen);
|
||||
mController.updateState(mCategoryPrimary);
|
||||
verify(mSettingsInjector).getInjectedSettings(
|
||||
any(Context.class), eq(UserHandle.myUserId()));
|
||||
}
|
||||
@@ -178,7 +150,6 @@ public class LocationInjectedServicesPreferenceControllerTest {
|
||||
enforcingUsers);
|
||||
|
||||
mController.displayPreference(mScreen);
|
||||
mController.updateState(mCategoryPrimary);
|
||||
verify(mSettingsInjector).getInjectedSettings(
|
||||
any(Context.class), eq(UserHandle.USER_CURRENT));
|
||||
}
|
||||
@@ -216,7 +187,6 @@ public class LocationInjectedServicesPreferenceControllerTest {
|
||||
when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(componentName);
|
||||
|
||||
mController.displayPreference(mScreen);
|
||||
mController.updateState(mCategoryPrimary);
|
||||
|
||||
assertThat(pref.isEnabled()).isFalse();
|
||||
assertThat(pref.isDisabledByAdmin()).isTrue();
|
||||
|
||||
@@ -160,9 +160,9 @@ public class RecentConversationsPreferenceControllerTest {
|
||||
true);
|
||||
|
||||
assertThat(mController.getSummary(ccw).toString()).contains(
|
||||
ccw.getParentNotificationChannelGroup().getName());
|
||||
ccw.getNotificationChannelGroup().getName());
|
||||
assertThat(mController.getSummary(ccw).toString()).contains(
|
||||
ccw.getParentNotificationChannel().getName());
|
||||
ccw.getNotificationChannel().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -175,7 +175,7 @@ public class RecentConversationsPreferenceControllerTest {
|
||||
true);
|
||||
|
||||
assertThat(mController.getSummary(ccw).toString()).isEqualTo(
|
||||
ccw.getParentNotificationChannel().getName());
|
||||
ccw.getNotificationChannel().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -207,7 +207,7 @@ public class RecentConversationsPreferenceControllerTest {
|
||||
ccw.getShortcutInfo().getPackage());
|
||||
assertThat(extras.getInt(AppInfoBase.ARG_PACKAGE_UID)).isEqualTo(ccw.getUid());
|
||||
assertThat(extras.getString(Settings.EXTRA_CHANNEL_ID)).isEqualTo(
|
||||
ccw.getParentNotificationChannel().getId());
|
||||
ccw.getNotificationChannel().getId());
|
||||
assertThat(extras.getString(Settings.EXTRA_CONVERSATION_ID)).isEqualTo(
|
||||
ccw.getShortcutInfo().getId());
|
||||
}
|
||||
@@ -230,7 +230,7 @@ public class RecentConversationsPreferenceControllerTest {
|
||||
// expected since it tries to launch an activity
|
||||
}
|
||||
verify(mBackend).createConversationNotificationChannel(
|
||||
si.getPackage(), ccw.getUid(), ccw.getParentNotificationChannel(), si.getId());
|
||||
si.getPackage(), ccw.getUid(), ccw.getNotificationChannel(), si.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -45,5 +45,4 @@ public class CardPreferenceTest {
|
||||
public void getLayoutResource() {
|
||||
assertThat(mCardPreference.getLayoutResource()).isEqualTo(R.layout.card_preference_layout);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.os.Looper;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.ServiceState;
|
||||
import android.telephony.SignalStrength;
|
||||
@@ -81,6 +82,8 @@ import java.util.List;
|
||||
public class SubscriptionsPreferenceControllerTest {
|
||||
private static final String KEY = "preference_group";
|
||||
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
private SubscriptionManager mSubscriptionManager;
|
||||
@Mock
|
||||
@@ -121,10 +124,12 @@ public class SubscriptionsPreferenceControllerTest {
|
||||
when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
|
||||
when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager);
|
||||
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
|
||||
when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
|
||||
when(mConnectivityManager.getActiveNetwork()).thenReturn(mActiveNetwork);
|
||||
when(mConnectivityManager.getNetworkCapabilities(mActiveNetwork))
|
||||
.thenReturn(mNetworkCapabilities);
|
||||
when(mUserManager.isAdminUser()).thenReturn(true);
|
||||
when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycleRegistry);
|
||||
|
||||
mPreferenceManager = new PreferenceManager(mContext);
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.widget;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.settings.testutils.ResourcesUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
/** Unittest for GearPreference */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class GearPreferenceTest {
|
||||
@Mock
|
||||
private GearPreference.OnGearClickListener mOnGearClickListener;
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private GearPreference mGearPreference;
|
||||
private PreferenceViewHolder mViewHolder;
|
||||
private View mGearView;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mGearPreference =
|
||||
new GearPreference(mContext, null);
|
||||
int layoutId = ResourcesUtils.getResourcesId(mContext, "layout", "preference_widget_gear");
|
||||
PreferenceViewHolder holder =
|
||||
PreferenceViewHolder.createInstanceForTests(
|
||||
LayoutInflater.from(ApplicationProvider.getApplicationContext())
|
||||
.inflate(layoutId, null));
|
||||
mViewHolder = spy(holder);
|
||||
mGearView = new View(mContext, null);
|
||||
int gearId = ResourcesUtils.getResourcesId(mContext, "id", "settings_button");
|
||||
when(mViewHolder.findViewById(gearId)).thenReturn(mGearView);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_gearIsVisible() {
|
||||
mGearPreference.setOnGearClickListener(mOnGearClickListener);
|
||||
|
||||
mGearPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
assertThat(mGearView.getVisibility()).isEqualTo(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_gearIsGone() {
|
||||
mGearPreference.setOnGearClickListener(null);
|
||||
|
||||
mGearPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
assertThat(mGearView.getVisibility()).isEqualTo(View.GONE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.widget;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.settings.testutils.ResourcesUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
/** Unittest for MutableGearPreference */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class MutableGearPreferenceTest {
|
||||
@Mock
|
||||
private MutableGearPreference.OnGearClickListener mOnGearClickListener;
|
||||
|
||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private MutableGearPreference mMutableGearPreference;
|
||||
private PreferenceViewHolder mViewHolder;
|
||||
private ImageView mGearView;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mMutableGearPreference =
|
||||
new MutableGearPreference(mContext, null);
|
||||
int layoutId =
|
||||
ResourcesUtils.getResourcesId(mContext, "layout", "preference_widget_gear");
|
||||
PreferenceViewHolder holder =
|
||||
PreferenceViewHolder.createInstanceForTests(
|
||||
LayoutInflater.from(ApplicationProvider.getApplicationContext())
|
||||
.inflate(layoutId, null));
|
||||
mViewHolder = spy(holder);
|
||||
mGearView = spy(new ImageView(mContext, null));
|
||||
int gearId = ResourcesUtils.getResourcesId(mContext, "id", "settings_button");
|
||||
when(mViewHolder.findViewById(gearId)).thenReturn(mGearView);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_gearChangeAlpha() {
|
||||
mMutableGearPreference.setGearEnabled(false);
|
||||
mMutableGearPreference.setOnGearClickListener(mOnGearClickListener);
|
||||
|
||||
mMutableGearPreference.onBindViewHolder(mViewHolder);
|
||||
|
||||
verify(mGearView).setImageAlpha(anyInt());
|
||||
}
|
||||
|
||||
private static int getDisabledAlphaValue(Context context) {
|
||||
TypedValue value = new TypedValue();
|
||||
context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, value, true);
|
||||
return (int) (value.getFloat() * 255);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user