Snap for 5476769 from a713243db4 to qt-release
Change-Id: I4f3b34b738480149937cf26278fb2c637acf2fd1
This commit is contained in:
@@ -2692,10 +2692,12 @@
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="false" />
|
||||
|
||||
<activity android:name=".sim.SimDialogActivity"
|
||||
android:theme="@style/Theme.AlertDialog"
|
||||
android:label="@string/sim_settings_title"
|
||||
android:excludeFromRecents="true">
|
||||
<activity
|
||||
android:name=".sim.SimDialogActivity"
|
||||
android:theme="@style/Theme.AlertDialog"
|
||||
android:label="@string/sim_settings_title"
|
||||
android:launchMode="singleTop"
|
||||
android:excludeFromRecents="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
</intent-filter>
|
||||
@@ -2907,7 +2909,7 @@
|
||||
android:launchMode="singleInstance"
|
||||
android:theme="@android:style/Theme.NoDisplay">
|
||||
<intent-filter>
|
||||
<action android:name="android.settings.VIEW_ADVANCED_POWER_USAGE_DETAIL" />
|
||||
<action android:name="android.settings.APP_BATTERY_SETTINGS" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="package" />
|
||||
</intent-filter>
|
||||
|
||||
26
res/drawable/dark_theme.xml
Normal file
26
res/drawable/dark_theme.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2019 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="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0"
|
||||
android:tint="?android:attr/colorAccent">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,22C17.52,22 22,17.52 22,12 22,6.48 17.52,2 12,2 6.48,2 2,6.48 2,12 2,17.52 6.48,22 12,22ZM12,3.915c3.889,0 8,4.005 8,8.085 0,4.08 -3.927,7.992 -7.928,7.992z"/>
|
||||
</vector>
|
||||
@@ -13,17 +13,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0"
|
||||
android:tint="?android:attr/colorAccent">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M16.67,4H14.5V2h-5v2H7.33C6.6,4 6,4.6 6,5.33V15v5.67C6,21.4 6.6,22 7.33,22h9.33C17.4,22 18,21.4 18,20.67V15V5.33C18,4.6 17.4,4 16.67,4zM16,15v5H8v-5V6h8V15z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15,12l-2,0l0,-2l-2,0l0,2l-2,0l0,2l2,0l0,2l2,0l0,-2l2,0z"/>
|
||||
</vector>
|
||||
<com.android.settings.widget.TintDrawable
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@drawable/ic_battery_status_bad_24dp"
|
||||
android:tint="?android:attr/colorAccent" />
|
||||
|
||||
@@ -13,19 +13,7 @@
|
||||
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:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0"
|
||||
android:tint="?android:attr/colorAccent">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15,4V3H9v1H4v2h1v13c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V6h1V4H15zM17,19H7V6h10V19z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9,8h2v9h-2z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M13,8h2v9h-2z"/>
|
||||
</vector>
|
||||
<com.android.settings.widget.TintDrawable
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@drawable/ic_delete"
|
||||
android:tint="?android:attr/colorAccent" />
|
||||
|
||||
@@ -13,12 +13,7 @@
|
||||
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:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M1,9l2,2c4.97,-4.97 13.03,-4.97 18,0l2,-2C16.93,2.93 7.08,2.93 1,9zM9,17l3,3l3,-3C13.35,15.34 10.66,15.34 9,17zM5,13l2,2c2.76,-2.76 7.24,-2.76 10,0l2,-2C15.14,9.14 8.87,9.14 5,13z"/>
|
||||
</vector>
|
||||
<com.android.settings.widget.TintDrawable
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@drawable/ic_settings_wireless"
|
||||
android:tint="@android:color/white" />
|
||||
@@ -14,13 +14,7 @@
|
||||
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="26dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="26"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillAlpha="0.3"
|
||||
android:fillColor="?attr/wifi_signal_color"
|
||||
android:pathData="M13.0,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.4,6.5L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
|
||||
</vector>
|
||||
<com.android.settings.widget.TintDrawable
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@*android:drawable/ic_wifi_signal_0"
|
||||
android:tint="?attr/wifi_signal_color" />
|
||||
@@ -14,16 +14,7 @@
|
||||
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="26dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="26"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillAlpha="0.3"
|
||||
android:fillColor="?attr/wifi_signal_color"
|
||||
android:pathData="M13.1,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.5,6.5L13.1,22.0L13.1,22.0L13.1,22.0L13.1,22.0L13.1,22.0z"/>
|
||||
<path
|
||||
android:fillColor="?attr/wifi_signal_color"
|
||||
android:pathData="M13.1,22.0l5.5,-6.8c-0.2,-0.2 -2.3,-1.9 -5.5,-1.9s-5.3,1.8 -5.5,1.9L13.1,22.0L13.1,22.0L13.1,22.0L13.1,22.0L13.1,22.0z"/>
|
||||
</vector>
|
||||
<com.android.settings.widget.TintDrawable
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@*android:drawable/ic_wifi_signal_1"
|
||||
android:tint="?attr/wifi_signal_color" />
|
||||
@@ -14,16 +14,7 @@
|
||||
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="26dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="26"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillAlpha="0.3"
|
||||
android:fillColor="?attr/wifi_signal_color"
|
||||
android:pathData="M13.0,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.4,6.5L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
|
||||
<path
|
||||
android:fillColor="?attr/wifi_signal_color"
|
||||
android:pathData="M13.0,22.0l7.6,-9.4C20.3,12.4 17.4,10.0 13.0,10.0s-7.3,2.4 -7.6,2.7L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
|
||||
</vector>
|
||||
<com.android.settings.widget.TintDrawable
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@*android:drawable/ic_wifi_signal_2"
|
||||
android:tint="?attr/wifi_signal_color" />
|
||||
|
||||
@@ -14,16 +14,7 @@
|
||||
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="26dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="26"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillAlpha="0.3"
|
||||
android:fillColor="?attr/wifi_signal_color"
|
||||
android:pathData="M13.0,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.4,6.5L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
|
||||
<path
|
||||
android:fillColor="?attr/wifi_signal_color"
|
||||
android:pathData="M13.0,22.0l9.2,-11.4c-0.4,-0.3 -3.9,-3.2 -9.2,-3.2s-8.9,3.0 -9.2,3.2L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
|
||||
</vector>
|
||||
<com.android.settings.widget.TintDrawable
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@*android:drawable/ic_wifi_signal_3"
|
||||
android:tint="?attr/wifi_signal_color" />
|
||||
@@ -14,12 +14,7 @@
|
||||
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="26dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="26"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="?attr/wifi_signal_color"
|
||||
android:pathData="M13.0,22.0L25.6,6.5C25.1,6.1 20.3,2.1 13.0,2.1S0.9,6.1 0.4,6.5L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0L13.0,22.0z"/>
|
||||
</vector>
|
||||
<com.android.settings.widget.TintDrawable
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@*android:drawable/ic_wifi_signal_4"
|
||||
android:tint="?attr/wifi_signal_color" />
|
||||
@@ -15,50 +15,60 @@
|
||||
limitations under the License
|
||||
-->
|
||||
|
||||
<!-- Note: There is a landscape version of this layout. -->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/panel_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingBottom="24dp"
|
||||
android:paddingTop="18dp"
|
||||
android:textColor="?android:attr/colorPrimary"
|
||||
android:textSize="20sp"/>
|
||||
|
||||
<include layout="@layout/panel_slice_list"/>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/panel_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/settings_panel_background" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:id="@+id/see_more"
|
||||
style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:text="@string/see_more"/>
|
||||
<TextView
|
||||
android:id="@+id/panel_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:paddingBottom="24dp"
|
||||
android:paddingTop="18dp"
|
||||
android:textColor="?android:attr/colorPrimary"
|
||||
android:textSize="20sp"/>
|
||||
|
||||
<Space
|
||||
android:layout_weight="1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent" />
|
||||
<include layout="@layout/horizontal_divider"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/done"
|
||||
style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:text="@string/done"/>
|
||||
<!-- Note: There is a landscape version of panel_slice_list which supports scrolling. -->
|
||||
<include layout="@layout/panel_slice_list"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/see_more"
|
||||
style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:text="@string/see_more"/>
|
||||
|
||||
<Space
|
||||
android:layout_weight="1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/done"
|
||||
style="@android:style/Widget.DeviceDefault.Button.Borderless.Colored"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:text="@string/done"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
@@ -28,7 +28,7 @@
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/conversation_background"
|
||||
android:background="?android:attr/colorBackgroundFloating"
|
||||
android:paddingTop="@dimen/conversation_message_list_padding"
|
||||
android:paddingStart="@dimen/conversation_message_list_padding"
|
||||
android:paddingEnd="@dimen/conversation_message_list_padding"
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
android:id="@+id/main_content_scrollable_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:importantForAccessibility="no"
|
||||
app:layout_behavior="com.android.settings.widget.FloatingAppBarScrollingViewBehavior">
|
||||
|
||||
<LinearLayout
|
||||
|
||||
@@ -15,6 +15,5 @@
|
||||
-->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/main_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:animateLayoutChanges="true"/>
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"/>
|
||||
@@ -15,7 +15,6 @@
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<color name="switchbar_text_color">@android:color/black</color>
|
||||
<color name="switchbar_switch_track_tint">#82000000</color>
|
||||
<color name="switchbar_switch_thumb_tint">@android:color/black</color>
|
||||
<color name="homepage_accessibility_background">#783BE5</color>
|
||||
|
||||
@@ -164,6 +164,11 @@
|
||||
<attr name="textOff" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="TintDrawable">
|
||||
<attr name="android:tint" />
|
||||
<attr name="android:drawable" />
|
||||
</declare-styleable>
|
||||
|
||||
<attr name="twoStateButtonPreferenceStyle" format="reference" />
|
||||
|
||||
<attr name="fingerprint_layout_theme" format="reference" />
|
||||
|
||||
@@ -63,7 +63,6 @@
|
||||
<color name="timestamp_text_incoming">#99ffffff</color>
|
||||
<color name="message_bubble_incoming">#689f38</color>
|
||||
<color name="message_bubble_outgoing">#ffffffff</color>
|
||||
<color name="conversation_background">#eeeeee</color>
|
||||
<color name="message_icon_background_incoming">#689f38</color>
|
||||
<color name="message_icon_text_incoming">#ffffffff</color>
|
||||
<color name="message_icon_background_outgoing">#4285f4</color>
|
||||
@@ -103,7 +102,7 @@
|
||||
<color name="contextual_card_background">@*android:color/background_device_default_light</color>
|
||||
<!-- End of dashboard/homepage icon background colors -->
|
||||
|
||||
<color name="switchbar_text_color">@android:color/white</color>
|
||||
<color name="switchbar_background_color">@*android:color/material_grey_600</color>
|
||||
<color name="switchbar_switch_track_tint">#BFFFFFFF</color>
|
||||
<color name="switchbar_switch_thumb_tint">@android:color/white</color>
|
||||
|
||||
|
||||
@@ -2791,7 +2791,7 @@
|
||||
<!-- Display settings screen, display white balance settings title [CHAR LIMIT=30] -->
|
||||
<string name="display_white_balance_title">Display white balance</string>
|
||||
<!-- Display settings screen, setting option name to enable adaptive sleep [CHAR LIMIT=30] -->
|
||||
<string name="adaptive_sleep_title">Screen aware</string>
|
||||
<string name="adaptive_sleep_title">Screen attention</string>
|
||||
<!-- Setting option summary when adaptive sleep is on [CHAR LIMIT=NONE] -->
|
||||
<string name="adaptive_sleep_summary_on">On / Screen won’t turn off if you’re looking at it</string>
|
||||
<!-- Setting option summary when adaptive sleep is off [CHAR LIMIT=NONE] -->
|
||||
@@ -2799,7 +2799,7 @@
|
||||
<!-- Description about the feature adaptive sleep [CHAR LIMIT=NONE]-->
|
||||
<string name="adaptive_sleep_description">Prevents your screen from turning off if you’re looking at it.</string>
|
||||
<!-- Description feature's privacy sensitive details to make sure users understand what feature users, what it saves/sends etc [CHAR LIMIT=NONE]-->
|
||||
<string name="adaptive_sleep_privacy">Screen aware uses the front camera to see if someone is looking at the screen. It works on device, and images are never stored or sent to Google.</string>
|
||||
<string name="adaptive_sleep_privacy">Screen attention uses the front camera to see if someone is looking at the screen. It works on device, and images are never stored or sent to Google.</string>
|
||||
|
||||
|
||||
<!-- Night display screen, setting option name to enable night display (renamed "Night Light" with title caps). [CHAR LIMIT=30] -->
|
||||
@@ -9900,17 +9900,14 @@
|
||||
<string name="demo_mode">System UI demo mode</string>
|
||||
|
||||
<!-- [CHAR LIMIT=60] Name of setting that changes the UI to dark -->
|
||||
<string name="dark_ui_mode">Theme</string>
|
||||
|
||||
<!-- [CHAR LIMIT=60] Name of dev option that changes the color of the UI -->
|
||||
<string name="dark_ui_mode_title">Choose Theme</string>
|
||||
|
||||
<!-- [CHAR_LIMIT=NONE] Summary that is shown in the footer when light mode is selected -->
|
||||
<string name="dark_ui_settings_light_summary">This setting also applies to apps</string>
|
||||
<string name="dark_ui_mode">Dark Theme</string>
|
||||
|
||||
<!-- [CHAR_LIMIT=NONE] Summary that is shown in the footer when dark mode is selected -->
|
||||
<string name="dark_ui_settings_dark_summary">Supported apps will also switch to dark theme</string>
|
||||
|
||||
<!-- [CHAR_LIMIT=40] Positive button text in dark theme notification -->
|
||||
<string name="dark_ui_settings_dialog_acknowledge">Got it</string>
|
||||
|
||||
<!-- [CHAR LIMIT=60] Name of dev option to enable extra quick settings tiles -->
|
||||
<string name="quick_settings_developer_tiles">Quick settings developer tiles</string>
|
||||
|
||||
@@ -11025,12 +11022,12 @@
|
||||
<!-- Message for forget passpoint dialog [CHAR LIMIT=none] -->
|
||||
<string name="forget_passpoint_dialog_message">You may lose access to any remaining time or data. Check with your provider before removing.</string>
|
||||
|
||||
<!-- Keywords for Content Capture / Smart Suggestions feature [CHAR_LIMIT=none] -->
|
||||
<string name="keywords_content_capture">content capture, smart suggestions</string>
|
||||
<!-- Keywords for Content Capture feature [CHAR_LIMIT=none] -->
|
||||
<string name="keywords_content_capture">content capture</string>
|
||||
<!-- Title of the 'Content Capture' feature toggle in the Settings -> Privacy screen [CHAR LIMIT=none]-->
|
||||
<string name="content_capture">Smart Suggestions</string>
|
||||
<!-- Description of the 'Content Capture / Smart Suggestions' feature toggle in the Settings -> Privacy screen [CHAR LIMIT=NONE]-->
|
||||
<string name="content_capture_summary">Allow Android to save information seen on your screen or heard in video or audio content. Android makes helpful suggestions based on your device activity.</string>
|
||||
<string name="content_capture">Content Capture</string>
|
||||
<!-- Description of the 'Content Capture' feature toggle in the Settings -> Privacy screen [CHAR LIMIT=NONE]-->
|
||||
<string name="content_capture_summary">Allow apps to send content to the Android system</string>
|
||||
|
||||
<!-- Title for the button to initiate a heap dump for the system server. [CHAR LIMIT=NONE] -->
|
||||
<string name="capture_system_heap_dump_title">Capture system heap dump</string>
|
||||
|
||||
@@ -87,10 +87,10 @@
|
||||
<item name="android:backgroundDimEnabled">false</item>
|
||||
</style>
|
||||
|
||||
<style name="ThemeOverlay.SwitchBar.Settings" parent="@android:style/ThemeOverlay.Material.ActionBar">
|
||||
<style name="ThemeOverlay.SwitchBar.Settings" parent="@*android:style/ThemeOverlay.DeviceDefault.ActionBar">
|
||||
<item name="switchBarMarginStart">@dimen/switchbar_subsettings_margin_start</item>
|
||||
<item name="switchBarMarginEnd">@dimen/switchbar_subsettings_margin_end</item>
|
||||
<item name="switchBarBackgroundColor">?android:attr/textColorSecondary</item>
|
||||
<item name="switchBarBackgroundColor">@color/switchbar_background_color</item>
|
||||
<item name="switchBarBackgroundActivatedColor">?android:attr/colorAccent</item>
|
||||
<item name="switchBarRestrictionIcon">@*android:drawable/ic_info</item>
|
||||
</style>
|
||||
@@ -203,7 +203,7 @@
|
||||
|
||||
<!-- Note that Dialog themes do not set list dividers -->
|
||||
<style name="Theme.BottomDialog" parent="@*android:style/Theme.DeviceDefault.Settings.Dialog">
|
||||
<item name="android:windowBackground">@drawable/settings_panel_background</item>
|
||||
<item name="android:windowBackground">@null</item>
|
||||
<item name="android:dividerHorizontal">@*android:drawable/list_divider_material</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:listDivider">@*android:drawable/list_divider_material</item>
|
||||
|
||||
@@ -191,12 +191,14 @@
|
||||
</style>
|
||||
|
||||
<style name="SuwAlertDialogThemeCompat" parent="@style/Theme.AppCompat.Dialog.Alert">
|
||||
<item name="android:windowSoftInputMode">adjustResize</item>
|
||||
<!-- copied from Theme.DeviceDefault.Light.Dialog.Alert -->
|
||||
<item name="colorAccent">@*android:color/accent_device_default_light</item>
|
||||
<item name="dialogCornerRadius">@*android:dimen/config_dialogCornerRadius</item>
|
||||
</style>
|
||||
|
||||
<style name="SuwAlertDialogThemeCompat.Light" parent="@style/Theme.AppCompat.Light.Dialog.Alert">
|
||||
<item name="android:windowSoftInputMode">adjustResize</item>
|
||||
<!-- copied from Theme.DeviceDefault.Light.Dialog.Alert -->
|
||||
<item name="colorAccent">@*android:color/accent_device_default_light</item>
|
||||
<item name="dialogCornerRadius">@*android:dimen/config_dialogCornerRadius</item>
|
||||
|
||||
@@ -58,11 +58,10 @@
|
||||
android:title="@string/screen_zoom_title"
|
||||
settings:searchable="false"/>
|
||||
|
||||
<Preference
|
||||
<SwitchPreference
|
||||
android:key="dark_ui_mode_accessibility"
|
||||
android:fragment="com.android.settings.display.DarkUISettings"
|
||||
android:title="@string/dark_ui_mode"
|
||||
settings:searchable="false" />
|
||||
settings:searchable="false"/>
|
||||
|
||||
<Preference
|
||||
android:fragment="com.android.settings.accessibility.MagnificationPreferenceFragment"
|
||||
|
||||
@@ -56,11 +56,10 @@
|
||||
</com.android.settingslib.RestrictedPreference>
|
||||
|
||||
|
||||
<Preference
|
||||
<SwitchPreference
|
||||
android:key="dark_ui_mode"
|
||||
android:fragment="com.android.settings.display.DarkUISettings"
|
||||
android:title="@string/dark_ui_mode"
|
||||
settings:searchable="false"
|
||||
settings:keywords="@string/keywords_dark_ui_mode"
|
||||
settings:controller="com.android.settings.display.DarkUIPreferenceController"/>
|
||||
|
||||
<!-- Cross-listed item, if you change this, also change it in power_usage_summary.xml -->
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
settings:useAdminDisabledSummary="true"
|
||||
settings:keywords="@string/keywords_sounds_and_notifications_interruptions"
|
||||
settings:allowDividerAbove="true"
|
||||
settings:controller="com.android.settings.notification.ZenModeSoundSettingsPreferenceController"/>
|
||||
settings:controller="com.android.settings.notification.ZenModePreferenceController"/>
|
||||
|
||||
<Preference
|
||||
android:key="gesture_prevent_ringing_sound"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:key="zen_mode_settings"
|
||||
android:title="@string/zen_mode_settings_title"
|
||||
settings:keywords="@string/keywords_zen_mode_settings">
|
||||
settings:searchable="false">
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="zen_mode_settings_category_behavior"
|
||||
@@ -66,11 +66,13 @@
|
||||
|
||||
<!-- Turn on DND button -->
|
||||
<com.android.settingslib.widget.LayoutPreference
|
||||
android:key="zen_mode_settings_button_container"
|
||||
android:key="zen_mode_toggle"
|
||||
android:title="@string/zen_mode_settings_title"
|
||||
android:selectable="false"
|
||||
android:layout="@layout/zen_mode_settings_button"
|
||||
settings:allowDividerAbove="true"
|
||||
settings:allowDividerBelow="true"/>
|
||||
settings:allowDividerBelow="true"
|
||||
settings:keywords="@string/keywords_zen_mode_settings"/>
|
||||
|
||||
<!-- Footer that shows if user is put into alarms only or total silence mode by an app -->
|
||||
<com.android.settingslib.widget.FooterPreference/>
|
||||
|
||||
@@ -18,11 +18,13 @@ package com.android.settings;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.provider.SearchIndexableResource;
|
||||
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.display.BrightnessLevelPreferenceController;
|
||||
import com.android.settings.display.CameraGesturePreferenceController;
|
||||
import com.android.settings.display.DarkUIPreferenceController;
|
||||
import com.android.settings.display.LiftToWakePreferenceController;
|
||||
import com.android.settings.display.NightDisplayPreferenceController;
|
||||
import com.android.settings.display.NightModePreferenceController;
|
||||
@@ -62,6 +64,12 @@ public class DisplaySettings extends DashboardFragment {
|
||||
return R.xml.display_settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
use(DarkUIPreferenceController.class).setParentFragment(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
|
||||
return buildPreferenceControllers(context, getSettingsLifecycle());
|
||||
|
||||
@@ -639,12 +639,7 @@ public class SettingsActivity extends SettingsBaseActivity
|
||||
showDev, isAdmin)
|
||||
|| somethingChanged;
|
||||
|
||||
// For profiles, we want them to be included in the profile select dialog even if
|
||||
// backup is not activated.
|
||||
// For other users, enable/disable backup settings depending on whether backup is activated
|
||||
// for the user.
|
||||
boolean enableBackupTile = um.isManagedProfile()
|
||||
|| new BackupSettingsHelper(this).isBackupServiceActive();
|
||||
boolean enableBackupTile = new BackupSettingsHelper(this).showBackupSettingsForUser();
|
||||
somethingChanged = setTileEnabled(changedList, new ComponentName(packageName,
|
||||
UserBackupSettingsActivity.class.getName()), enableBackupTile, isAdmin)
|
||||
|| somethingChanged;
|
||||
|
||||
@@ -244,7 +244,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
private SwitchPreference mToggleInversionPreference;
|
||||
private ColorInversionPreferenceController mInversionPreferenceController;
|
||||
private AccessibilityHearingAidPreferenceController mHearingAidPreferenceController;
|
||||
private Preference mDarkUIModePreference;
|
||||
private SwitchPreference mDarkUIModePreference;
|
||||
private DarkUIPreferenceController mDarkUIPreferenceController;
|
||||
private LiveCaptionPreferenceController mLiveCaptionPreferenceController;
|
||||
|
||||
@@ -524,8 +524,8 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
|
||||
mDarkUIModePreference = findPreference(DARK_UI_MODE_PREFERENCE);
|
||||
mDarkUIPreferenceController = new DarkUIPreferenceController(getContext(),
|
||||
DARK_UI_MODE_PREFERENCE);
|
||||
mDarkUIPreferenceController.setParentFragment(this);
|
||||
mDarkUIPreferenceController.displayPreference(getPreferenceScreen());
|
||||
mDarkUIModePreference.setSummary(mDarkUIPreferenceController.getSummary());
|
||||
}
|
||||
|
||||
private void updateAllPreferences() {
|
||||
|
||||
@@ -28,6 +28,9 @@ public class BackupInactivePreferenceController extends BasePreferenceController
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
if (!new BackupSettingsHelper(mContext).showBackupSettingsForUser()) {
|
||||
return AVAILABLE_UNSEARCHABLE;
|
||||
}
|
||||
if (PrivacySettingsUtils.isInvisibleKey(mContext, PrivacySettingsUtils.BACKUP_INACTIVE)) {
|
||||
return UNSUPPORTED_ON_DEVICE;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,14 @@ public class BackupSettingsHelper {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public boolean showBackupSettingsForUser() {
|
||||
// For profiles, we want them to be included in the profile select dialog even if
|
||||
// backup is not activated.
|
||||
// For other users, enable/disable backup settings depending on whether backup is activated
|
||||
// for the user.
|
||||
return UserManager.get(mContext).isManagedProfile() || isBackupServiceActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is only one profile, show whether the backup is on or off.
|
||||
* Otherwise, show nothing.
|
||||
|
||||
@@ -98,7 +98,7 @@ public class UserBackupSettingsActivity extends FragmentActivity implements Inde
|
||||
*/
|
||||
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider() {
|
||||
private static final String BACKUP_SEARCH_INDEX_KEY = "backup";
|
||||
private static final String BACKUP_SEARCH_INDEX_KEY = "Backup";
|
||||
|
||||
@Override
|
||||
public List<SearchIndexableRaw> getRawDataToIndex(Context context,
|
||||
@@ -119,6 +119,15 @@ public class UserBackupSettingsActivity extends FragmentActivity implements Inde
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getNonIndexableKeys(Context context) {
|
||||
final List<String> keys = super.getNonIndexableKeys(context);
|
||||
if (!new BackupSettingsHelper(context).showBackupSettingsForUser()) {
|
||||
keys.add(BACKUP_SEARCH_INDEX_KEY);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
};
|
||||
|
||||
@VisibleForTesting
|
||||
|
||||
@@ -44,7 +44,7 @@ public abstract class SliderPreferenceController extends BasePreferenceControlle
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value of the Slider's position based on the range: [0, maxSteps).
|
||||
* @return the value of the Slider's position based on the range: [min, max].
|
||||
*/
|
||||
public abstract int getSliderPosition();
|
||||
|
||||
@@ -57,9 +57,14 @@ public abstract class SliderPreferenceController extends BasePreferenceControlle
|
||||
public abstract boolean setSliderPosition(int position);
|
||||
|
||||
/**
|
||||
* @return the number of steps supported by the slider.
|
||||
* @return the maximum value supported by the slider.
|
||||
*/
|
||||
public abstract int getMaxSteps();
|
||||
public abstract int getMax();
|
||||
|
||||
/**
|
||||
* @return the minimum value supported by the slider.
|
||||
*/
|
||||
public abstract int getMin();
|
||||
|
||||
@Override
|
||||
public int getSliceType() {
|
||||
|
||||
@@ -99,22 +99,23 @@ public class DataUsageList extends DataUsageBaseFragment {
|
||||
}
|
||||
};
|
||||
|
||||
private ChartDataUsagePreference mChart;
|
||||
private TelephonyManager mTelephonyManager;
|
||||
|
||||
@VisibleForTesting
|
||||
NetworkTemplate mTemplate;
|
||||
@VisibleForTesting
|
||||
int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
@VisibleForTesting
|
||||
int mNetworkType;
|
||||
@VisibleForTesting
|
||||
Spinner mCycleSpinner;
|
||||
@VisibleForTesting
|
||||
LoadingViewController mLoadingViewController;
|
||||
|
||||
private ChartDataUsagePreference mChart;
|
||||
private TelephonyManager mTelephonyManager;
|
||||
private List<NetworkCycleChartData> mCycleData;
|
||||
private ArrayList<Long> mCycles;
|
||||
|
||||
private LoadingViewController mLoadingViewController;
|
||||
private UidDetailProvider mUidDetailProvider;
|
||||
private CycleAdapter mCycleAdapter;
|
||||
private Spinner mCycleSpinner;
|
||||
private Preference mUsageAmount;
|
||||
private PreferenceGroup mApps;
|
||||
private View mHeader;
|
||||
@@ -158,6 +159,7 @@ public class DataUsageList extends DataUsageBaseFragment {
|
||||
.launch();
|
||||
});
|
||||
mCycleSpinner = mHeader.findViewById(R.id.filter_spinner);
|
||||
mCycleSpinner.setVisibility(View.GONE);
|
||||
mCycleAdapter = new CycleAdapter(mCycleSpinner.getContext(), new SpinnerInterface() {
|
||||
@Override
|
||||
public void setAdapter(CycleAdapter cycleAdapter) {
|
||||
@@ -276,7 +278,8 @@ public class DataUsageList extends DataUsageBaseFragment {
|
||||
* Update chart sweeps and cycle list to reflect {@link NetworkPolicy} for
|
||||
* current {@link #mTemplate}.
|
||||
*/
|
||||
private void updatePolicy() {
|
||||
@VisibleForTesting
|
||||
void updatePolicy() {
|
||||
final NetworkPolicy policy = services.mPolicyEditor.getPolicy(mTemplate);
|
||||
final View configureButton = mHeader.findViewById(R.id.filter_settings);
|
||||
//SUB SELECT
|
||||
@@ -486,7 +489,8 @@ public class DataUsageList extends DataUsageBaseFragment {
|
||||
}
|
||||
};
|
||||
|
||||
private final LoaderCallbacks<List<NetworkCycleChartData>> mNetworkCycleDataCallbacks =
|
||||
@VisibleForTesting
|
||||
final LoaderCallbacks<List<NetworkCycleChartData>> mNetworkCycleDataCallbacks =
|
||||
new LoaderCallbacks<List<NetworkCycleChartData>>() {
|
||||
@Override
|
||||
public Loader<List<NetworkCycleChartData>> onCreateLoader(int id, Bundle args) {
|
||||
@@ -503,6 +507,7 @@ public class DataUsageList extends DataUsageBaseFragment {
|
||||
mCycleData = data;
|
||||
// calculate policy cycles based on available data
|
||||
updatePolicy();
|
||||
mCycleSpinner.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,9 +15,14 @@ package com.android.settings.display;
|
||||
|
||||
import static android.provider.Settings.System.ADAPTIVE_SLEEP;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
@@ -27,16 +32,24 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle
|
||||
private final String SYSTEM_KEY = ADAPTIVE_SLEEP;
|
||||
private final int DEFAULT_VALUE = 0;
|
||||
|
||||
private final boolean hasSufficientPermissions;
|
||||
|
||||
public AdaptiveSleepPreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
|
||||
final PackageManager packageManager = mContext.getPackageManager();
|
||||
final String attentionPackage = packageManager.getAttentionServicePackageName();
|
||||
hasSufficientPermissions = attentionPackage != null && packageManager.checkPermission(
|
||||
Manifest.permission.CAMERA, attentionPackage) == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return Settings.System.getInt(mContext.getContentResolver(),
|
||||
return hasSufficientPermissions && Settings.System.getInt(mContext.getContentResolver(),
|
||||
SYSTEM_KEY, DEFAULT_VALUE) != DEFAULT_VALUE;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
Settings.System.putInt(mContext.getContentResolver(), SYSTEM_KEY,
|
||||
@@ -64,4 +77,15 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle
|
||||
? R.string.adaptive_sleep_summary_on
|
||||
: R.string.adaptive_sleep_summary_off);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
final Preference preference = screen.findPreference(SYSTEM_KEY);
|
||||
|
||||
if (preference != null) {
|
||||
preference.setEnabled(hasSufficientPermissions);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.display;
|
||||
|
||||
import static com.android.settings.display.DarkUIPreferenceController.DARK_MODE_PREFS;
|
||||
import static com.android.settings.display.DarkUIPreferenceController.PREF_DARK_MODE_DIALOG_SEEN;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
|
||||
public class DarkUIInfoDialogFragment extends InstrumentedDialogFragment
|
||||
implements DialogInterface.OnClickListener{
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
// TODO(b/130251804): Add metrics constant in followup change to avoid merge conflict in
|
||||
// beta cherrypick
|
||||
return 0;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
Context context = getContext();
|
||||
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
|
||||
LayoutInflater inflater = LayoutInflater.from(dialog.getContext());
|
||||
View titleView = inflater.inflate(R.layout.settings_dialog_title, null);
|
||||
((ImageView) titleView.findViewById(R.id.settings_icon))
|
||||
.setImageDrawable(context.getDrawable(R.drawable.dark_theme));
|
||||
((TextView) titleView.findViewById(R.id.settings_title)).setText(R.string.dark_ui_mode);
|
||||
|
||||
dialog.setCustomTitle(titleView)
|
||||
.setMessage(R.string.dark_ui_settings_dark_summary)
|
||||
.setPositiveButton(
|
||||
R.string.dark_ui_settings_dialog_acknowledge,
|
||||
this);
|
||||
return dialog.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(@NonNull DialogInterface dialog) {
|
||||
enableDarkTheme();
|
||||
super.onDismiss(dialog);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
// We have to manually dismiss the dialog because changing night mode causes it to
|
||||
// recreate itself.
|
||||
dialogInterface.dismiss();
|
||||
enableDarkTheme();
|
||||
}
|
||||
|
||||
private void enableDarkTheme() {
|
||||
final Context context = getContext();
|
||||
if (context != null) {
|
||||
Settings.Secure.putInt(context.getContentResolver(),
|
||||
Settings.Secure.DARK_MODE_DIALOG_SEEN,
|
||||
DarkUIPreferenceController.DIALOG_SEEN);
|
||||
context.getSystemService(UiModeManager.class)
|
||||
.setNightMode(UiModeManager.MODE_NIGHT_YES);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,37 +18,66 @@ package com.android.settings.display;
|
||||
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
|
||||
public class DarkUIPreferenceController extends BasePreferenceController {
|
||||
public class DarkUIPreferenceController extends TogglePreferenceController {
|
||||
|
||||
public static final String DARK_MODE_PREFS = "dark_mode_prefs";
|
||||
public static final String PREF_DARK_MODE_DIALOG_SEEN = "dark_mode_dialog_seen";
|
||||
public static final int DIALOG_SEEN = 1;
|
||||
private UiModeManager mUiModeManager;
|
||||
private Context mContext;
|
||||
private Fragment mFragment;
|
||||
|
||||
public DarkUIPreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
mContext = context;
|
||||
mUiModeManager = context.getSystemService(UiModeManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
final boolean dialogSeen =
|
||||
Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.DARK_MODE_DIALOG_SEEN, 0) == DIALOG_SEEN;
|
||||
if (!dialogSeen && isChecked) {
|
||||
showDarkModeDialog();
|
||||
return false;
|
||||
}
|
||||
mUiModeManager.setNightMode(isChecked
|
||||
? UiModeManager.MODE_NIGHT_YES
|
||||
: UiModeManager.MODE_NIGHT_NO);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void showDarkModeDialog() {
|
||||
final DarkUIInfoDialogFragment frag = new DarkUIInfoDialogFragment();
|
||||
if (mFragment.getFragmentManager() != null) {
|
||||
frag.show(mFragment.getFragmentManager(), getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setUiModeManager(UiModeManager uiModeManager) {
|
||||
mUiModeManager = uiModeManager;
|
||||
}
|
||||
|
||||
public void setParentFragment(Fragment fragment) {
|
||||
mFragment = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
return DarkUISettingsRadioButtonsController.modeToDescription(
|
||||
mContext, mUiModeManager.getNightMode());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.display;
|
||||
|
||||
import android.app.UiModeManager;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.search.Indexable;
|
||||
import com.android.settings.widget.RadioButtonPickerFragment;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
import com.android.settingslib.widget.CandidateInfo;
|
||||
import com.android.settingslib.widget.FooterPreference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The screen for selecting the dark theme preference for this device. Automatically updates
|
||||
* the associated footer view with any needed information.
|
||||
*/
|
||||
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
||||
public class DarkUISettings extends RadioButtonPickerFragment implements Indexable {
|
||||
|
||||
private DarkUISettingsRadioButtonsController mController;
|
||||
private Preference mFooter;
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.dark_ui_settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
// TODO(b/128686189): add illustration once it is ready
|
||||
setIllustration(0, 0);
|
||||
mFooter = new FooterPreference(context);
|
||||
mFooter.setIcon(android.R.color.transparent);
|
||||
mController = new DarkUISettingsRadioButtonsController(context, mFooter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<? extends CandidateInfo> getCandidates() {
|
||||
final Context context = getContext();
|
||||
final List<CandidateInfo> candidates = new ArrayList<>();
|
||||
candidates.add(new DarkUISettingsCandidateInfo(
|
||||
DarkUISettingsRadioButtonsController.modeToDescription(
|
||||
context, UiModeManager.MODE_NIGHT_YES),
|
||||
/* summary */ null,
|
||||
DarkUISettingsRadioButtonsController.KEY_DARK,
|
||||
/* enabled */ true));
|
||||
candidates.add(new DarkUISettingsCandidateInfo(
|
||||
DarkUISettingsRadioButtonsController.modeToDescription(
|
||||
context, UiModeManager.MODE_NIGHT_NO),
|
||||
/* summary */ null,
|
||||
DarkUISettingsRadioButtonsController.KEY_LIGHT,
|
||||
/* enabled */ true));
|
||||
return candidates;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addStaticPreferences(PreferenceScreen screen) {
|
||||
screen.addPreference(mFooter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDefaultKey() {
|
||||
return mController.getDefaultKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean setDefaultKey(String key) {
|
||||
return mController.setDefaultKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.DARK_UI_SETTINGS;
|
||||
}
|
||||
|
||||
static class DarkUISettingsCandidateInfo extends CandidateInfo {
|
||||
|
||||
private final CharSequence mLabel;
|
||||
private final CharSequence mSummary;
|
||||
private final String mKey;
|
||||
|
||||
DarkUISettingsCandidateInfo(CharSequence label, CharSequence summary, String key,
|
||||
boolean enabled) {
|
||||
super(enabled);
|
||||
mLabel = label;
|
||||
mKey = key;
|
||||
mSummary = summary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence loadLabel() {
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable loadIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return mKey;
|
||||
}
|
||||
|
||||
public CharSequence getSummary() {
|
||||
return mSummary;
|
||||
}
|
||||
}
|
||||
|
||||
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider() {
|
||||
@Override
|
||||
public List<SearchIndexableResource> getXmlResourcesToIndex(
|
||||
Context context, boolean enabled) {
|
||||
final SearchIndexableResource sir = new SearchIndexableResource(context);
|
||||
sir.xmlResId = R.xml.dark_ui_settings;
|
||||
return Arrays.asList(sir);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.display;
|
||||
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
import androidx.preference.Preference;
|
||||
import com.android.settings.R;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
public class DarkUISettingsRadioButtonsController {
|
||||
|
||||
public static final String KEY_DARK = "key_dark_ui_settings_dark";
|
||||
public static final String KEY_LIGHT = "key_dark_ui_settings_light";
|
||||
|
||||
@VisibleForTesting
|
||||
UiModeManager mManager;
|
||||
|
||||
private Preference mFooter;
|
||||
|
||||
public DarkUISettingsRadioButtonsController(Context context, Preference footer) {
|
||||
mManager = context.getSystemService(UiModeManager.class);
|
||||
mFooter = footer;
|
||||
}
|
||||
|
||||
public String getDefaultKey() {
|
||||
final int mode = mManager.getNightMode();
|
||||
updateFooter();
|
||||
return mode == UiModeManager.MODE_NIGHT_YES ? KEY_DARK : KEY_LIGHT;
|
||||
}
|
||||
|
||||
public boolean setDefaultKey(String key) {
|
||||
switch(key) {
|
||||
case KEY_DARK:
|
||||
mManager.setNightMode(UiModeManager.MODE_NIGHT_YES);
|
||||
break;
|
||||
case KEY_LIGHT:
|
||||
mManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException(
|
||||
"Not a valid key for " + this.getClass().getSimpleName() + ": " + key);
|
||||
}
|
||||
updateFooter();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void updateFooter() {
|
||||
final int mode = mManager.getNightMode();
|
||||
switch (mode) {
|
||||
case UiModeManager.MODE_NIGHT_YES:
|
||||
mFooter.setSummary(R.string.dark_ui_settings_dark_summary);
|
||||
break;
|
||||
case UiModeManager.MODE_NIGHT_NO:
|
||||
case UiModeManager.MODE_NIGHT_AUTO:
|
||||
default:
|
||||
mFooter.setSummary(R.string.dark_ui_settings_light_summary);
|
||||
}
|
||||
}
|
||||
|
||||
public static String modeToDescription(Context context, int mode) {
|
||||
final String[] values = context.getResources().getStringArray(R.array.dark_ui_mode_entries);
|
||||
switch (mode) {
|
||||
case UiModeManager.MODE_NIGHT_YES:
|
||||
return values[0];
|
||||
case UiModeManager.MODE_NIGHT_NO:
|
||||
case UiModeManager.MODE_NIGHT_AUTO:
|
||||
default:
|
||||
return values[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,8 @@ public class NightDisplayIntensityPreferenceController extends SliderPreferenceC
|
||||
super.displayPreference(screen);
|
||||
final SeekBarPreference preference = screen.findPreference(getPreferenceKey());
|
||||
preference.setContinuousUpdates(true);
|
||||
preference.setMax(getMaxSteps());
|
||||
preference.setMax(getMax());
|
||||
preference.setMin(getMin());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,10 +76,15 @@ public class NightDisplayIntensityPreferenceController extends SliderPreferenceC
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSteps() {
|
||||
public int getMax() {
|
||||
return convertTemperature(ColorDisplayManager.getMinimumColorTemperature(mContext));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMin() {
|
||||
return ColorDisplayManager.getMinimumColorTemperature(mContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts and range-adjusts a raw value from the SeekBar (i.e. [0, maxTemp-minTemp]), or
|
||||
* converts an inverted and range-adjusted value to the raw SeekBar value, depending on the
|
||||
|
||||
@@ -160,7 +160,7 @@ public abstract class BatteryTip implements Comparable<BatteryTip>, Parcelable {
|
||||
}
|
||||
|
||||
/** Returns the color resid for tinting {@link #getIconId()} or {@link View#NO_ID} if none. */
|
||||
protected @IdRes int getIconTintColorId() {
|
||||
public @IdRes int getIconTintColorId() {
|
||||
return View.NO_ID;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,8 +102,15 @@ public class PreventRingingSwitchPreferenceController extends AbstractPreference
|
||||
|
||||
@Override
|
||||
public void onSwitchChanged(Switch switchView, boolean isChecked) {
|
||||
final int preventRingingSetting = Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.VOLUME_HUSH_GESTURE, Settings.Secure.VOLUME_HUSH_VIBRATE);
|
||||
final int newRingingSetting = preventRingingSetting == Settings.Secure.VOLUME_HUSH_OFF
|
||||
? Settings.Secure.VOLUME_HUSH_VIBRATE
|
||||
: preventRingingSetting;
|
||||
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.VOLUME_HUSH_GESTURE, isChecked ? Settings.Secure.VOLUME_HUSH_VIBRATE
|
||||
Settings.Secure.VOLUME_HUSH_GESTURE, isChecked
|
||||
? newRingingSetting
|
||||
: Settings.Secure.VOLUME_HUSH_OFF);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@ import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
@@ -39,6 +42,7 @@ import androidx.slice.builders.SliceAction;
|
||||
import com.android.internal.os.BatteryStatsHelper;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SubSettings;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.fuelgauge.BatteryStatsHelperLoader;
|
||||
import com.android.settings.fuelgauge.PowerUsageSummary;
|
||||
import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
|
||||
@@ -107,8 +111,12 @@ public class BatteryFixSlice implements CustomSliceable {
|
||||
if (batteryTip.getState() == BatteryTip.StateType.INVISIBLE) {
|
||||
continue;
|
||||
}
|
||||
final IconCompat icon = IconCompat.createWithResource(mContext,
|
||||
batteryTip.getIconId());
|
||||
final Drawable drawable = mContext.getDrawable(batteryTip.getIconId());
|
||||
drawable.setColorFilter(new PorterDuffColorFilter(
|
||||
mContext.getResources().getColor(batteryTip.getIconTintColorId()),
|
||||
PorterDuff.Mode.SRC_IN));
|
||||
|
||||
final IconCompat icon = Utils.createIconWithDrawable(drawable);
|
||||
final SliceAction primaryAction = SliceAction.createDeeplink(getPrimaryAction(),
|
||||
icon,
|
||||
ListBuilder.ICON_IMAGE,
|
||||
|
||||
@@ -154,16 +154,12 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
// TODO(b/123065955): Review latency of NotificationChannelSlice
|
||||
final List<PackageInfo> multiChannelPackages = getMultiChannelPackages(
|
||||
getRecentlyInstalledPackages());
|
||||
final PackageInfo packageInfo = getMaxSentNotificationsPackage(multiChannelPackages);
|
||||
|
||||
// Return a header with IsError flag, if package is not found.
|
||||
if (packageInfo == null) {
|
||||
mPackageName = getMaxSentNotificationsPackage(multiChannelPackages);
|
||||
if (mPackageName == null) {
|
||||
// Return a header with IsError flag, if package is not found.
|
||||
return listBuilder.setHeader(getNoSuggestedAppHeader())
|
||||
.setIsError(true).build();
|
||||
}
|
||||
|
||||
// Save eligible package name and its uid, they will be used in getIntent().
|
||||
mPackageName = packageInfo.packageName;
|
||||
mUid = getApplicationUid(mPackageName);
|
||||
|
||||
// Add notification channel header.
|
||||
@@ -177,7 +173,7 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
.setPrimaryAction(getPrimarySliceAction(icon, title, getIntent())));
|
||||
|
||||
// Add notification channel rows.
|
||||
final List<ListBuilder.RowBuilder> rows = getNotificationChannelRows(packageInfo, icon);
|
||||
final List<ListBuilder.RowBuilder> rows = getNotificationChannelRows(icon);
|
||||
for (ListBuilder.RowBuilder rowBuilder : rows) {
|
||||
listBuilder.addRow(rowBuilder);
|
||||
}
|
||||
@@ -282,8 +278,7 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
.setPrimaryAction(primarySliceActionForNoSuggestedApp);
|
||||
}
|
||||
|
||||
private List<ListBuilder.RowBuilder> getNotificationChannelRows(PackageInfo packageInfo,
|
||||
IconCompat icon) {
|
||||
private List<ListBuilder.RowBuilder> getNotificationChannelRows(IconCompat icon) {
|
||||
final List<ListBuilder.RowBuilder> notificationChannelRows = new ArrayList<>();
|
||||
final List<NotificationChannel> displayableChannels = getDisplayableChannels(mAppRow);
|
||||
|
||||
@@ -388,14 +383,14 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private PackageInfo getMaxSentNotificationsPackage(List<PackageInfo> packageInfoList) {
|
||||
private String getMaxSentNotificationsPackage(List<PackageInfo> packageInfoList) {
|
||||
if (packageInfoList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the package which has sent at least ~10 notifications and not turn off channels.
|
||||
int maxSentCount = 0;
|
||||
PackageInfo maxSentCountPackage = null;
|
||||
String maxSentCountPackage = null;
|
||||
for (PackageInfo packageInfo : packageInfoList) {
|
||||
final NotificationBackend.AppRow appRow = mNotificationBackend.loadAppRow(mContext,
|
||||
mContext.getPackageManager(), packageInfo);
|
||||
@@ -408,7 +403,7 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
final int sentCount = appRow.sentByApp.sentCount;
|
||||
if (sentCount >= MIN_NOTIFICATION_SENT_COUNT && sentCount > maxSentCount) {
|
||||
maxSentCount = sentCount;
|
||||
maxSentCountPackage = packageInfo;
|
||||
maxSentCountPackage = packageInfo.packageName;
|
||||
mAppRow = appRow;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.settings.homepage.contextualcards.slices;
|
||||
|
||||
import static android.app.slice.Slice.HINT_ERROR;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
@@ -117,6 +119,14 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, Life
|
||||
return;
|
||||
}
|
||||
|
||||
if (slice.hasHint(HINT_ERROR)) {
|
||||
Log.w(TAG, "Slice has HINT_ERROR, skipping rendering. uri=" + slice.getUri());
|
||||
mSliceLiveDataMap.get(slice.getUri()).removeObservers(mLifecycleOwner);
|
||||
mContext.getContentResolver().notifyChange(CardContentProvider.REFRESH_CARD_URI,
|
||||
null);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (holder.getItemViewType()) {
|
||||
case VIEW_TYPE_DEFERRED_SETUP:
|
||||
mDeferredSetupCardHelper.bindView(holder, card, slice);
|
||||
|
||||
@@ -21,6 +21,7 @@ import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.UserManager;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.euicc.EuiccManager;
|
||||
@@ -49,6 +50,7 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController
|
||||
private static final String KEY = "mobile_network_list";
|
||||
|
||||
private SubscriptionManager mSubscriptionManager;
|
||||
private UserManager mUserManager;
|
||||
private SubscriptionsChangeListener mChangeListener;
|
||||
private AddPreference mPreference;
|
||||
|
||||
@@ -70,6 +72,7 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController
|
||||
public MobileNetworkSummaryController(Context context, Lifecycle lifecycle) {
|
||||
super(context);
|
||||
mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
|
||||
mUserManager = context.getSystemService(UserManager.class);
|
||||
if (lifecycle != null) {
|
||||
mChangeListener = new SubscriptionsChangeListener(context, this);
|
||||
lifecycle.addObserver(this);
|
||||
@@ -137,6 +140,8 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController
|
||||
startAddSimFlow();
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
mPreference.setEnabled(false);
|
||||
}
|
||||
} else {
|
||||
// We have one or more existing subscriptions, so we want the plus button if eSIM is
|
||||
@@ -160,7 +165,7 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return !Utils.isWifiOnly(mContext);
|
||||
return !Utils.isWifiOnly(mContext) && mUserManager.isAdminUser();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -74,4 +74,8 @@ public class AudioHelper {
|
||||
public int getMaxVolume(int stream) {
|
||||
return mAudioManager.getStreamMaxVolume(stream);
|
||||
}
|
||||
|
||||
public int getMinVolume(int stream) {
|
||||
return mAudioManager.getStreamMinVolume(stream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,6 @@ public class RemoteVolumePreferenceController extends VolumeSeekBarPreferenceCon
|
||||
@VisibleForTesting
|
||||
static final int REMOTE_VOLUME = 100;
|
||||
|
||||
private MediaSessionManager mMediaSessionManager;
|
||||
private MediaSessions mMediaSessions;
|
||||
@VisibleForTesting
|
||||
MediaSession.Token mActiveToken;
|
||||
@@ -86,28 +85,39 @@ public class RemoteVolumePreferenceController extends VolumeSeekBarPreferenceCon
|
||||
|
||||
public RemoteVolumePreferenceController(Context context) {
|
||||
super(context, KEY_REMOTE_VOLUME);
|
||||
mMediaSessionManager = context.getSystemService(MediaSessionManager.class);
|
||||
mMediaSessions = new MediaSessions(context, Looper.getMainLooper(), mCallbacks);
|
||||
updateToken(getActiveRemoteToken(mContext));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
final List<MediaController> controllers = mMediaSessionManager.getActiveSessions(null);
|
||||
// Always return true to make it indexed in database
|
||||
return AVAILABLE_UNSEARCHABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link android.media.session.MediaSession.Token} for active remote token, or
|
||||
* {@code null} if there is no active remote token.
|
||||
*/
|
||||
public static MediaSession.Token getActiveRemoteToken(Context context) {
|
||||
final MediaSessionManager sessionManager = context.getSystemService(
|
||||
MediaSessionManager.class);
|
||||
final List<MediaController> controllers = sessionManager.getActiveSessions(null);
|
||||
for (MediaController mediaController : controllers) {
|
||||
final MediaController.PlaybackInfo pi = mediaController.getPlaybackInfo();
|
||||
if (isRemote(pi)) {
|
||||
updateToken(mediaController.getSessionToken());
|
||||
return AVAILABLE;
|
||||
return mediaController.getSessionToken();
|
||||
}
|
||||
}
|
||||
|
||||
// No active remote media at this point
|
||||
return CONDITIONALLY_UNAVAILABLE;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mPreference.setVisible(mActiveToken != null);
|
||||
if (mMediaController != null) {
|
||||
updatePreference(mPreference, mActiveToken, mMediaController.getPlaybackInfo());
|
||||
}
|
||||
@@ -150,7 +160,7 @@ public class RemoteVolumePreferenceController extends VolumeSeekBarPreferenceCon
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSteps() {
|
||||
public int getMax() {
|
||||
if (mPreference != null) {
|
||||
return mPreference.getMax();
|
||||
}
|
||||
@@ -161,6 +171,14 @@ public class RemoteVolumePreferenceController extends VolumeSeekBarPreferenceCon
|
||||
return playbackInfo != null ? playbackInfo.getMaxVolume() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMin() {
|
||||
if (mPreference != null) {
|
||||
return mPreference.getMin();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSliceable() {
|
||||
return TextUtils.equals(getPreferenceKey(), KEY_REMOTE_VOLUME);
|
||||
|
||||
@@ -80,11 +80,6 @@ public class VolumeSeekBarPreference extends SeekBarPreference {
|
||||
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelectable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setStream(int stream) {
|
||||
mStream = stream;
|
||||
setMax(mAudioManager.getStreamMaxVolume(mStream));
|
||||
|
||||
@@ -92,13 +92,21 @@ public abstract class VolumeSeekBarPreferenceController extends
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSteps() {
|
||||
public int getMax() {
|
||||
if (mPreference != null) {
|
||||
return mPreference.getMax();
|
||||
}
|
||||
return mHelper.getMaxVolume(getAudioStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMin() {
|
||||
if (mPreference != null) {
|
||||
return mPreference.getMin();
|
||||
}
|
||||
return mHelper.getMinVolume(getAudioStream());
|
||||
}
|
||||
|
||||
protected abstract int getAudioStream();
|
||||
|
||||
protected abstract int getMuteIcon();
|
||||
|
||||
@@ -33,11 +33,12 @@ import com.android.settingslib.widget.LayoutPreference;
|
||||
public class ZenModeButtonPreferenceController extends AbstractZenModePreferenceController
|
||||
implements PreferenceControllerMixin {
|
||||
|
||||
public static final String KEY = "zen_mode_toggle";
|
||||
|
||||
private static final String TAG = "EnableZenModeButton";
|
||||
protected static final String KEY = "zen_mode_settings_button_container";
|
||||
private final FragmentManager mFragment;
|
||||
private Button mZenButtonOn;
|
||||
private Button mZenButtonOff;
|
||||
private FragmentManager mFragment;
|
||||
|
||||
public ZenModeButtonPreferenceController(Context context, Lifecycle lifecycle, FragmentManager
|
||||
fragment) {
|
||||
@@ -60,13 +61,13 @@ public class ZenModeButtonPreferenceController extends AbstractZenModePreference
|
||||
super.updateState(preference);
|
||||
|
||||
if (null == mZenButtonOn) {
|
||||
mZenButtonOn = (Button) ((LayoutPreference) preference)
|
||||
mZenButtonOn = ((LayoutPreference) preference)
|
||||
.findViewById(R.id.zen_mode_settings_turn_on_button);
|
||||
updateZenButtonOnClickListener();
|
||||
}
|
||||
|
||||
if (null == mZenButtonOff) {
|
||||
mZenButtonOff = (Button) ((LayoutPreference) preference)
|
||||
mZenButtonOff = ((LayoutPreference) preference)
|
||||
.findViewById(R.id.zen_mode_settings_turn_off_button);
|
||||
mZenButtonOff.setOnClickListener(v -> {
|
||||
mMetricsFeatureProvider.action(mContext,
|
||||
|
||||
@@ -328,7 +328,6 @@ public class ZenModeSettings extends ZenModeSettingsBase {
|
||||
public List<String> getNonIndexableKeys(Context context) {
|
||||
List<String> keys = super.getNonIndexableKeys(context);
|
||||
keys.add(ZenModeDurationPreferenceController.KEY);
|
||||
keys.add(ZenModeButtonPreferenceController.KEY);
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ package com.android.settings.notification;
|
||||
|
||||
import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
|
||||
|
||||
import static com.android.settings.notification.ZenModeSoundSettingsPreferenceController.ZEN_MODE_KEY;
|
||||
|
||||
import android.annotation.ColorInt;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
@@ -47,6 +45,8 @@ public class ZenModeSliceBuilder {
|
||||
|
||||
private static final String TAG = "ZenModeSliceBuilder";
|
||||
|
||||
private static final String ZEN_MODE_SLICE_KEY = ZenModeButtonPreferenceController.KEY;
|
||||
|
||||
/**
|
||||
* Action notifying a change on the Zen Mode Slice.
|
||||
*/
|
||||
@@ -78,7 +78,8 @@ public class ZenModeSliceBuilder {
|
||||
final PendingIntent primaryAction = getPrimaryAction(context);
|
||||
final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryAction,
|
||||
(IconCompat) null /* icon */, ListBuilder.ICON_IMAGE, title);
|
||||
final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction, null /* actionTitle */,
|
||||
final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction,
|
||||
null /* actionTitle */,
|
||||
isZenModeEnabled);
|
||||
|
||||
return new ListBuilder(context, CustomSliceRegistry.ZEN_MODE_SLICE_URI,
|
||||
@@ -110,10 +111,10 @@ public class ZenModeSliceBuilder {
|
||||
}
|
||||
|
||||
public static Intent getIntent(Context context) {
|
||||
final Uri contentUri = new Uri.Builder().appendPath(ZEN_MODE_KEY).build();
|
||||
final Uri contentUri = new Uri.Builder().appendPath(ZEN_MODE_SLICE_KEY).build();
|
||||
final String screenTitle = context.getText(R.string.zen_mode_settings_title).toString();
|
||||
return SliceBuilderUtils.buildSearchResultPageIntent(context,
|
||||
ZenModeSettings.class.getName(), ZEN_MODE_KEY, screenTitle,
|
||||
ZenModeSettings.class.getName(), ZEN_MODE_SLICE_KEY, screenTitle,
|
||||
SettingsEnums.NOTIFICATION_ZEN_MODE)
|
||||
.setClassName(context.getPackageName(), SubSettings.class.getName())
|
||||
.setData(contentUri);
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.notification;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
public class ZenModeSoundSettingsPreferenceController extends ZenModePreferenceController {
|
||||
|
||||
public static final String ZEN_MODE_KEY = "zen_mode";
|
||||
|
||||
public ZenModeSoundSettingsPreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
}
|
||||
@@ -16,13 +16,20 @@
|
||||
|
||||
package com.android.settings.panel;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
@@ -30,8 +37,12 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.slice.Slice;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.slice.SliceMetadata;
|
||||
import androidx.slice.widget.SliceLiveData;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
@@ -40,10 +51,24 @@ import com.android.settings.panel.PanelLoggingContract.PanelClosedKeys;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
import com.google.android.setupdesign.DividerItemDecoration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PanelFragment extends Fragment {
|
||||
|
||||
private static final String TAG = "PanelFragment";
|
||||
|
||||
/**
|
||||
* Duration of the animation entering or exiting the screen, in milliseconds.
|
||||
*/
|
||||
private static final int DURATION_ANIMATE_PANEL_MS = 250;
|
||||
|
||||
/**
|
||||
* Duration of timeout waiting for Slice data to bind, in milliseconds.
|
||||
*/
|
||||
private static final int DURATION_SLICE_BINDING_TIMEOUT_MS = 250;
|
||||
|
||||
private View mLayoutView;
|
||||
private TextView mTitleView;
|
||||
private Button mSeeMoreButton;
|
||||
private Button mDoneButton;
|
||||
@@ -53,20 +78,40 @@ public class PanelFragment extends Fragment {
|
||||
private MetricsFeatureProvider mMetricsProvider;
|
||||
private String mPanelClosedKey;
|
||||
|
||||
private final List<LiveData<Slice>> mSliceLiveData = new ArrayList<>();
|
||||
|
||||
@VisibleForTesting
|
||||
PanelSlicesAdapter mAdapter;
|
||||
PanelSlicesLoaderCountdownLatch mPanelSlicesLoaderCountdownLatch;
|
||||
|
||||
private ViewTreeObserver.OnPreDrawListener mOnPreDrawListener = () -> {
|
||||
return false;
|
||||
};
|
||||
|
||||
private final ViewTreeObserver.OnGlobalLayoutListener mOnGlobalLayoutListener =
|
||||
new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
animateIn();
|
||||
if (mPanelSlices != null) {
|
||||
mPanelSlices.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private PanelSlicesAdapter mAdapter;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
final FragmentActivity activity = getActivity();
|
||||
final View view = inflater.inflate(R.layout.panel_layout, container, false);
|
||||
|
||||
mPanelSlices = view.findViewById(R.id.panel_parent_layout);
|
||||
mSeeMoreButton = view.findViewById(R.id.see_more);
|
||||
mDoneButton = view.findViewById(R.id.done);
|
||||
mTitleView = view.findViewById(R.id.panel_title);
|
||||
mLayoutView = inflater.inflate(R.layout.panel_layout, container, false);
|
||||
|
||||
mPanelSlices = mLayoutView.findViewById(R.id.panel_parent_layout);
|
||||
mSeeMoreButton = mLayoutView.findViewById(R.id.see_more);
|
||||
mDoneButton = mLayoutView.findViewById(R.id.done);
|
||||
mTitleView = mLayoutView.findViewById(R.id.panel_title);
|
||||
|
||||
final Bundle arguments = getArguments();
|
||||
final String panelType =
|
||||
@@ -82,6 +127,24 @@ public class PanelFragment extends Fragment {
|
||||
.getPanel(activity, panelType, mediaPackageName);
|
||||
|
||||
mMetricsProvider = FeatureFactory.getFactory(activity).getMetricsFeatureProvider();
|
||||
|
||||
mPanelSlices.setLayoutManager(new LinearLayoutManager((activity)));
|
||||
|
||||
// Add predraw listener to remove the animation and while we wait for Slices to load.
|
||||
mLayoutView.getViewTreeObserver().addOnPreDrawListener(mOnPreDrawListener);
|
||||
|
||||
// Start loading Slices. When finished, the Panel will animate in.
|
||||
loadAllSlices();
|
||||
|
||||
mTitleView.setText(mPanel.getTitle());
|
||||
mSeeMoreButton.setOnClickListener(getSeeMoreListener());
|
||||
mDoneButton.setOnClickListener(getCloseListener());
|
||||
|
||||
// If getSeeMoreIntent() is null, hide the mSeeMoreButton.
|
||||
if (mPanel.getSeeMoreIntent() == null) {
|
||||
mSeeMoreButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// Log panel opened.
|
||||
mMetricsProvider.action(
|
||||
0 /* attribution */,
|
||||
@@ -90,27 +153,114 @@ public class PanelFragment extends Fragment {
|
||||
callingPackageName,
|
||||
0 /* value */);
|
||||
|
||||
mAdapter = new PanelSlicesAdapter(this, mPanel);
|
||||
return mLayoutView;
|
||||
}
|
||||
|
||||
mPanelSlices.setHasFixedSize(true);
|
||||
mPanelSlices.setLayoutManager(new LinearLayoutManager((activity)));
|
||||
mPanelSlices.setAdapter(mAdapter);
|
||||
private void loadAllSlices() {
|
||||
mSliceLiveData.clear();
|
||||
final List<Uri> sliceUris = mPanel.getSlices();
|
||||
mPanelSlicesLoaderCountdownLatch = new PanelSlicesLoaderCountdownLatch(sliceUris.size());
|
||||
|
||||
DividerItemDecoration itemDecoration = new DividerItemDecoration(getActivity());
|
||||
itemDecoration.setDividerCondition(DividerItemDecoration.DIVIDER_CONDITION_BOTH);
|
||||
mPanelSlices.addItemDecoration(itemDecoration);
|
||||
for (Uri uri : sliceUris) {
|
||||
final LiveData<Slice> sliceLiveData = SliceLiveData.fromUri(getActivity(), uri);
|
||||
|
||||
mTitleView.setText(mPanel.getTitle());
|
||||
// Add slice first to make it in order. Will remove it later if there's an error.
|
||||
mSliceLiveData.add(sliceLiveData);
|
||||
|
||||
mSeeMoreButton.setOnClickListener(getSeeMoreListener());
|
||||
mDoneButton.setOnClickListener(getCloseListener());
|
||||
sliceLiveData.observe(getViewLifecycleOwner(), slice -> {
|
||||
// If the Slice has already loaded, do nothing.
|
||||
if (mPanelSlicesLoaderCountdownLatch.isSliceLoaded(uri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//If getSeeMoreIntent() is null, hide the mSeeMoreButton.
|
||||
if (mPanel.getSeeMoreIntent() == null) {
|
||||
mSeeMoreButton.setVisibility(View.GONE);
|
||||
/**
|
||||
* Watching for the {@link Slice} to load.
|
||||
* <p>
|
||||
* If the Slice comes back {@code null} or with the Error attribute, remove the
|
||||
* Slice data from the list, and mark the Slice as loaded.
|
||||
* <p>
|
||||
* If the Slice has come back fully loaded, then mark the Slice as loaded. No
|
||||
* other actions required since we already have the Slice data in the list.
|
||||
* <p>
|
||||
* If the Slice does not match the above condition, we will still want to mark
|
||||
* it as loaded after 250ms timeout to avoid delay showing up the panel for
|
||||
* too long. Since we are still having the Slice data in the list, the Slice
|
||||
* will show up later once it is loaded.
|
||||
*/
|
||||
final SliceMetadata metadata = SliceMetadata.from(getActivity(), slice);
|
||||
if (slice == null || metadata.isErrorSlice()) {
|
||||
mSliceLiveData.remove(sliceLiveData);
|
||||
mPanelSlicesLoaderCountdownLatch.markSliceLoaded(uri);
|
||||
} else if (metadata.getLoadingState() == SliceMetadata.LOADED_ALL) {
|
||||
mPanelSlicesLoaderCountdownLatch.markSliceLoaded(uri);
|
||||
} else {
|
||||
Handler handler = new Handler();
|
||||
handler.postDelayed(() -> {
|
||||
mPanelSlicesLoaderCountdownLatch.markSliceLoaded(uri);
|
||||
loadPanelWhenReady();
|
||||
}, DURATION_SLICE_BINDING_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
loadPanelWhenReady();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return view;
|
||||
/**
|
||||
* When all of the Slices have loaded for the first time, then we can setup the
|
||||
* {@link RecyclerView}.
|
||||
* <p>
|
||||
* When the Recyclerview has been laid out, we can begin the animation with the
|
||||
* {@link mOnGlobalLayoutListener}, which calls {@link #animateIn()}.
|
||||
*/
|
||||
private void loadPanelWhenReady() {
|
||||
if (mPanelSlicesLoaderCountdownLatch.isPanelReadyToLoad()) {
|
||||
mAdapter = new PanelSlicesAdapter(
|
||||
this, mSliceLiveData, mPanel.getMetricsCategory());
|
||||
mPanelSlices.setAdapter(mAdapter);
|
||||
mPanelSlices.getViewTreeObserver()
|
||||
.addOnGlobalLayoutListener(mOnGlobalLayoutListener);
|
||||
|
||||
DividerItemDecoration itemDecoration = new DividerItemDecoration(getActivity());
|
||||
itemDecoration
|
||||
.setDividerCondition(DividerItemDecoration.DIVIDER_CONDITION_BOTH);
|
||||
mPanelSlices.addItemDecoration(itemDecoration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Animate a Panel onto the screen.
|
||||
* <p>
|
||||
* Takes the entire panel and animates in from behind the navigation bar.
|
||||
* <p>
|
||||
* Relies on the Panel being having a fixed height to begin the animation.
|
||||
*/
|
||||
private void animateIn() {
|
||||
final View panelContent = mLayoutView.findViewById(R.id.panel_container);
|
||||
final AnimatorSet animatorSet = buildAnimatorSet(mLayoutView, panelContent.getHeight(),
|
||||
0.0f, new DecelerateInterpolator());
|
||||
final ValueAnimator animator = new ValueAnimator();
|
||||
animator.setFloatValues(0.0f, 1.0f);
|
||||
animatorSet.play(animator);
|
||||
animatorSet.start();
|
||||
// Remove the predraw listeners on the Panel.
|
||||
mLayoutView.getViewTreeObserver().removeOnPreDrawListener(mOnPreDrawListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an {@link AnimatorSet} to bring the Panel, {@param parentView}in our out of the screen,
|
||||
* based on the positional parameters {@param startY}, {@param endY} and at the rate set by the
|
||||
* {@param interpolator}.
|
||||
*/
|
||||
@NonNull
|
||||
private static AnimatorSet buildAnimatorSet(@NonNull View parentView, float startY, float endY,
|
||||
@NonNull Interpolator interpolator) {
|
||||
final View sheet = parentView.findViewById(R.id.panel_container);
|
||||
final AnimatorSet animatorSet = new AnimatorSet();
|
||||
animatorSet.setDuration(DURATION_ANIMATE_PANEL_MS);
|
||||
animatorSet.setInterpolator(interpolator);
|
||||
animatorSet.playTogether(ObjectAnimator.ofFloat(sheet, View.TRANSLATION_Y, startY, endY));
|
||||
return animatorSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,7 +20,6 @@ import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_INDIC
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -30,13 +29,13 @@ import androidx.annotation.VisibleForTesting;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.widget.SliceLiveData;
|
||||
import androidx.slice.widget.SliceView;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.google.android.setupdesign.DividerItemDecoration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -45,14 +44,15 @@ import java.util.List;
|
||||
public class PanelSlicesAdapter
|
||||
extends RecyclerView.Adapter<PanelSlicesAdapter.SliceRowViewHolder> {
|
||||
|
||||
private final List<Uri> mSliceUris;
|
||||
private final List<LiveData<Slice>> mSliceLiveData;
|
||||
private final int mMetricsCategory;
|
||||
private final PanelFragment mPanelFragment;
|
||||
private final PanelContent mPanelContent;
|
||||
|
||||
public PanelSlicesAdapter(PanelFragment fragment, PanelContent panel) {
|
||||
public PanelSlicesAdapter(
|
||||
PanelFragment fragment, List<LiveData<Slice>> sliceLiveData, int metricsCategory) {
|
||||
mPanelFragment = fragment;
|
||||
mSliceUris = panel.getSlices();
|
||||
mPanelContent = panel;
|
||||
mSliceLiveData = new ArrayList<>(sliceLiveData);
|
||||
mMetricsCategory = metricsCategory;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -62,67 +62,60 @@ public class PanelSlicesAdapter
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
final View view = inflater.inflate(R.layout.panel_slice_row, viewGroup, false);
|
||||
|
||||
return new SliceRowViewHolder(view, mPanelContent);
|
||||
return new SliceRowViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull SliceRowViewHolder sliceRowViewHolder, int position) {
|
||||
sliceRowViewHolder.onBind(mPanelFragment, mSliceUris.get(position));
|
||||
sliceRowViewHolder.onBind(mSliceLiveData.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mSliceUris.size();
|
||||
return mSliceLiveData.size();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<Uri> getData() {
|
||||
return mSliceUris;
|
||||
List<LiveData<Slice>> getData() {
|
||||
return mSliceLiveData;
|
||||
}
|
||||
|
||||
/**
|
||||
* ViewHolder for binding Slices to SliceViews.
|
||||
*/
|
||||
public static class SliceRowViewHolder extends RecyclerView.ViewHolder
|
||||
public class SliceRowViewHolder extends RecyclerView.ViewHolder
|
||||
implements DividerItemDecoration.DividedViewHolder {
|
||||
|
||||
private final PanelContent mPanelContent;
|
||||
|
||||
private boolean mDividerAllowedAbove = true;
|
||||
|
||||
@VisibleForTesting
|
||||
LiveData<Slice> sliceLiveData;
|
||||
|
||||
@VisibleForTesting
|
||||
final SliceView sliceView;
|
||||
|
||||
public SliceRowViewHolder(View view, PanelContent panelContent) {
|
||||
public SliceRowViewHolder(View view) {
|
||||
super(view);
|
||||
sliceView = view.findViewById(R.id.slice_view);
|
||||
sliceView.setMode(SliceView.MODE_LARGE);
|
||||
sliceView.showTitleItems(true);
|
||||
mPanelContent = panelContent;
|
||||
}
|
||||
|
||||
public void onBind(PanelFragment fragment, Uri sliceUri) {
|
||||
final Context context = sliceView.getContext();
|
||||
sliceLiveData = SliceLiveData.fromUri(context, sliceUri);
|
||||
sliceLiveData.observe(fragment.getViewLifecycleOwner(), sliceView);
|
||||
public void onBind(LiveData<Slice> sliceLiveData) {
|
||||
sliceLiveData.observe(mPanelFragment.getViewLifecycleOwner(), sliceView);
|
||||
|
||||
// Do not show the divider above media devices switcher slice per request
|
||||
if (sliceUri.equals(MEDIA_OUTPUT_INDICATOR_SLICE_URI)) {
|
||||
final Slice slice = sliceLiveData.getValue();
|
||||
if (slice != null && slice.getUri().equals(MEDIA_OUTPUT_INDICATOR_SLICE_URI)) {
|
||||
mDividerAllowedAbove = false;
|
||||
}
|
||||
|
||||
// Log Panel interaction
|
||||
sliceView.setOnSliceActionListener(
|
||||
((eventInfo, sliceItem) -> {
|
||||
FeatureFactory.getFactory(context)
|
||||
FeatureFactory.getFactory(sliceView.getContext())
|
||||
.getMetricsFeatureProvider()
|
||||
.action(0 /* attribution */,
|
||||
SettingsEnums.ACTION_PANEL_INTERACTION,
|
||||
mPanelContent.getMetricsCategory(),
|
||||
sliceUri.toString() /* log key */,
|
||||
mMetricsCategory,
|
||||
sliceLiveData.toString() /* log key */,
|
||||
eventInfo.actionType /* value */);
|
||||
})
|
||||
);
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.panel;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.slice.Slice;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/**
|
||||
* Helper class to isolate the work tracking all of the {@link Slice Slices} being loaded.
|
||||
* <p>
|
||||
* Uses a {@link CountDownLatch} and a {@link Set} of Slices to track how many
|
||||
* Slices have been loaded. A Slice can only be counted as being loaded a single time, even
|
||||
* when they get updated later.
|
||||
* <p>
|
||||
* To use the class, pass the number of expected Slices to load into the constructor. For
|
||||
* every Slice that loads, call {@link #markSliceLoaded(Uri)} with the corresponding
|
||||
* {@link Uri}. Then check if all of the Slices have loaded with
|
||||
* {@link #isPanelReadyToLoad()}, which will return {@code true} the first time after all
|
||||
* Slices have loaded.
|
||||
*/
|
||||
public class PanelSlicesLoaderCountdownLatch {
|
||||
private final Set<Uri> mLoadedSlices;
|
||||
private final CountDownLatch mCountDownLatch;
|
||||
private boolean slicesReadyToLoad = false;
|
||||
|
||||
public PanelSlicesLoaderCountdownLatch(int countdownSize) {
|
||||
mLoadedSlices = new HashSet<>();
|
||||
mCountDownLatch = new CountDownLatch(countdownSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the {@param sliceUri} has been loaded: if not, then decrement the countdown
|
||||
* latch, and if so, then do nothing.
|
||||
*/
|
||||
public void markSliceLoaded(Uri sliceUri) {
|
||||
if (mLoadedSlices.contains(sliceUri)) {
|
||||
return;
|
||||
}
|
||||
mLoadedSlices.add(sliceUri);
|
||||
mCountDownLatch.countDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if the Slice has already been loaded.
|
||||
*/
|
||||
public boolean isSliceLoaded(Uri uri) {
|
||||
return mLoadedSlices.contains(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} when all Slices have loaded, and the Panel has not yet been loaded.
|
||||
*/
|
||||
public boolean isPanelReadyToLoad() {
|
||||
/**
|
||||
* Use {@link slicesReadyToLoad} to track whether or not the Panel has been loaded. We
|
||||
* only want to animate the Panel a single time.
|
||||
*/
|
||||
if ((mCountDownLatch.getCount() == 0) && !slicesReadyToLoad) {
|
||||
slicesReadyToLoad = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import android.net.Uri;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.notification.RemoteVolumePreferenceController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -54,7 +55,9 @@ public class VolumePanel implements PanelContent {
|
||||
@Override
|
||||
public List<Uri> getSlices() {
|
||||
final List<Uri> uris = new ArrayList<>();
|
||||
uris.add(VOLUME_REMOTE_MEDIA_URI);
|
||||
if (RemoteVolumePreferenceController.getActiveRemoteToken(mContext) != null) {
|
||||
uris.add(VOLUME_REMOTE_MEDIA_URI);
|
||||
}
|
||||
uris.add(VOLUME_MEDIA_URI);
|
||||
uris.add(MEDIA_OUTPUT_INDICATOR_SLICE_URI);
|
||||
uris.add(VOLUME_CALL_URI);
|
||||
|
||||
59
src/com/android/settings/sim/CallsSimListDialogFragment.java
Normal file
59
src/com/android/settings/sim/CallsSimListDialogFragment.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.sim;
|
||||
|
||||
import android.content.Context;
|
||||
import android.telecom.PhoneAccount;
|
||||
import android.telecom.PhoneAccountHandle;
|
||||
import android.telecom.TelecomManager;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Specialized version of SimListDialogFragment that fetches a list of SIMs which support calls.
|
||||
*/
|
||||
public class CallsSimListDialogFragment extends SimListDialogFragment {
|
||||
@Override
|
||||
protected List<SubscriptionInfo> getCurrentSubscriptions() {
|
||||
final Context context = getContext();
|
||||
final SubscriptionManager subscriptionManager = context.getSystemService(
|
||||
SubscriptionManager.class);
|
||||
final TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
|
||||
final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
|
||||
final List<PhoneAccountHandle> phoneAccounts =
|
||||
telecomManager.getCallCapablePhoneAccounts();
|
||||
final List<SubscriptionInfo> result = new ArrayList<>();
|
||||
|
||||
if (phoneAccounts == null) {
|
||||
return result;
|
||||
}
|
||||
for (PhoneAccountHandle handle : phoneAccounts) {
|
||||
final PhoneAccount phoneAccount = telecomManager.getPhoneAccount(handle);
|
||||
final int subId = telephonyManager.getSubIdForPhoneAccount(phoneAccount);
|
||||
|
||||
if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
||||
continue;
|
||||
}
|
||||
result.add(subscriptionManager.getActiveSubscriptionInfo(subId));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
101
src/com/android/settings/sim/PreferredSimDialogFragment.java
Normal file
101
src/com/android/settings/sim/PreferredSimDialogFragment.java
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.sim;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
/**
|
||||
* Presents a dialog asking the user if they want to update all services to use a given "preferred"
|
||||
* SIM. Typically this would be used in a case where a device goes from having multiple SIMs down to
|
||||
* only one.
|
||||
*/
|
||||
public class PreferredSimDialogFragment extends SimDialogFragment implements
|
||||
DialogInterface.OnClickListener {
|
||||
private static final String TAG = "PreferredSimDialogFrag";
|
||||
|
||||
public static PreferredSimDialogFragment newInstance() {
|
||||
final PreferredSimDialogFragment fragment = new PreferredSimDialogFragment();
|
||||
final Bundle args = initArguments(SimDialogActivity.PREFERRED_PICK,
|
||||
R.string.sim_preferred_title);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
final AlertDialog dialog = new AlertDialog.Builder(getContext())
|
||||
.setTitle(getTitleResId())
|
||||
.setPositiveButton(R.string.yes, this)
|
||||
.setNegativeButton(R.string.no, null)
|
||||
.create();
|
||||
updateDialog(dialog);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int buttonClicked) {
|
||||
if (buttonClicked != DialogInterface.BUTTON_POSITIVE) {
|
||||
return;
|
||||
}
|
||||
final SimDialogActivity activity = (SimDialogActivity) getActivity();
|
||||
final SubscriptionInfo info = getPreferredSubscription();
|
||||
if (info != null) {
|
||||
activity.onSubscriptionSelected(getDialogType(), info.getSubscriptionId());
|
||||
}
|
||||
}
|
||||
|
||||
public SubscriptionInfo getPreferredSubscription() {
|
||||
final Activity activity = getActivity();
|
||||
final int slotId = activity.getIntent().getIntExtra(SimDialogActivity.PREFERRED_SIM,
|
||||
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
|
||||
return getSubscriptionManager().getActiveSubscriptionInfoForSimSlotIndex(slotId);
|
||||
}
|
||||
|
||||
private void updateDialog(AlertDialog dialog) {
|
||||
final SubscriptionInfo info = getPreferredSubscription();
|
||||
if (info == null) {
|
||||
dismiss();
|
||||
return;
|
||||
}
|
||||
final String message =
|
||||
getContext().getString(R.string.sim_preferred_message, info.getDisplayName());
|
||||
dialog.setMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDialog() {
|
||||
updateDialog((AlertDialog) getDialog());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected SubscriptionManager getSubscriptionManager() {
|
||||
return getContext().getSystemService(SubscriptionManager.class);
|
||||
}
|
||||
}
|
||||
@@ -16,37 +16,30 @@
|
||||
|
||||
package com.android.settings.sim;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.res.Resources;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.telecom.PhoneAccount;
|
||||
import android.telecom.PhoneAccountHandle;
|
||||
import android.telecom.TelecomManager;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.TextView;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class SimDialogActivity extends Activity {
|
||||
/**
|
||||
* This activity provides singleton semantics per dialog type for showing various kinds of
|
||||
* dialogs asking the user to make choices about which SIM to use for various services
|
||||
* (calls, SMS, and data).
|
||||
*/
|
||||
public class SimDialogActivity extends FragmentActivity {
|
||||
private static String TAG = "SimDialogActivity";
|
||||
|
||||
public static String PREFERRED_SIM = "preferred_sim";
|
||||
@@ -60,276 +53,118 @@ public class SimDialogActivity extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final int dialogType = getIntent().getIntExtra(DIALOG_TYPE_KEY, INVALID_PICK);
|
||||
showOrUpdateDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
setIntent(intent);
|
||||
showOrUpdateDialog();
|
||||
}
|
||||
|
||||
private void showOrUpdateDialog() {
|
||||
final int dialogType = getIntent().getIntExtra(DIALOG_TYPE_KEY, INVALID_PICK);
|
||||
final String tag = Integer.toString(dialogType);
|
||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
SimDialogFragment fragment = (SimDialogFragment) fragmentManager.findFragmentByTag(tag);
|
||||
|
||||
if (fragment == null) {
|
||||
fragment = createFragment(dialogType);
|
||||
fragment.show(fragmentManager, tag);
|
||||
} else {
|
||||
fragment.updateDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private SimDialogFragment createFragment(int dialogType) {
|
||||
switch(dialogType) {
|
||||
case DATA_PICK:
|
||||
return SimListDialogFragment.newInstance(dialogType, R.string.select_sim_for_data,
|
||||
false /* includeAskEveryTime */);
|
||||
case CALLS_PICK:
|
||||
return CallsSimListDialogFragment.newInstance(dialogType, R.string.select_sim_for_calls,
|
||||
true /* includeAskEveryTime */);
|
||||
case SMS_PICK:
|
||||
return SimListDialogFragment.newInstance(dialogType, R.string.select_sim_for_sms,
|
||||
false /* includeAskEveryTime */);
|
||||
case PREFERRED_PICK:
|
||||
if (!getIntent().hasExtra(PREFERRED_SIM)) {
|
||||
throw new IllegalArgumentException("Missing required extra " + PREFERRED_SIM);
|
||||
}
|
||||
return PreferredSimDialogFragment.newInstance();
|
||||
default:
|
||||
throw new IllegalArgumentException( "Invalid dialog type " + dialogType + " sent.");
|
||||
}
|
||||
}
|
||||
|
||||
public void onSubscriptionSelected(int dialogType, int subId) {
|
||||
if (getSupportFragmentManager().findFragmentByTag(Integer.toString(dialogType)) == null) {
|
||||
Log.w(TAG, "onSubscriptionSelected ignored because stored fragment was null");
|
||||
return;
|
||||
}
|
||||
switch (dialogType) {
|
||||
case DATA_PICK:
|
||||
setDefaultDataSubId(subId);
|
||||
break;
|
||||
case CALLS_PICK:
|
||||
setDefaultCallsSubId(subId);
|
||||
break;
|
||||
case SMS_PICK:
|
||||
createDialog(this, dialogType).show();
|
||||
setDefaultSmsSubId(subId);
|
||||
break;
|
||||
case PREFERRED_PICK:
|
||||
displayPreferredDialog(getIntent().getIntExtra(PREFERRED_SIM, 0));
|
||||
setPreferredSim(subId);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid dialog type " + dialogType + " sent.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void displayPreferredDialog(final int slotId) {
|
||||
final Resources res = getResources();
|
||||
final Context context = getApplicationContext();
|
||||
final SubscriptionInfo sir = SubscriptionManager.from(context)
|
||||
.getActiveSubscriptionInfoForSimSlotIndex(slotId);
|
||||
|
||||
if (sir != null) {
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
|
||||
alertDialogBuilder.setTitle(R.string.sim_preferred_title);
|
||||
alertDialogBuilder.setMessage(res.getString(
|
||||
R.string.sim_preferred_message, sir.getDisplayName()));
|
||||
|
||||
alertDialogBuilder.setPositiveButton(R.string.yes, new
|
||||
DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
final int subId = sir.getSubscriptionId();
|
||||
PhoneAccountHandle phoneAccountHandle =
|
||||
subscriptionIdToPhoneAccountHandle(subId);
|
||||
setDefaultDataSubId(context, subId);
|
||||
setDefaultSmsSubId(context, subId);
|
||||
setUserSelectedOutgoingPhoneAccount(phoneAccountHandle);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
alertDialogBuilder.setNegativeButton(R.string.no, new
|
||||
DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog,int id) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
alertDialogBuilder.create().show();
|
||||
} else {
|
||||
finish();
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid dialog type " + dialogType + " sent.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void setDefaultDataSubId(final Context context, final int subId) {
|
||||
final SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
|
||||
final TelephonyManager telephonyManager = TelephonyManager.from(context)
|
||||
.createForSubscriptionId(subId);
|
||||
public void onFragmentDismissed(SimDialogFragment simDialogFragment) {
|
||||
final List<Fragment> fragments = getSupportFragmentManager().getFragments();
|
||||
if (fragments.size() == 1 && fragments.get(0) == simDialogFragment) {
|
||||
finishAndRemoveTask();
|
||||
}
|
||||
}
|
||||
|
||||
private void setDefaultDataSubId(final int subId) {
|
||||
final SubscriptionManager subscriptionManager = getSystemService(SubscriptionManager.class);
|
||||
final TelephonyManager telephonyManager = getSystemService(
|
||||
TelephonyManager.class).createForSubscriptionId(subId);
|
||||
subscriptionManager.setDefaultDataSubId(subId);
|
||||
telephonyManager.setDataEnabled(true);
|
||||
Toast.makeText(context, R.string.data_switch_started, Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, R.string.data_switch_started, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
private static void setDefaultSmsSubId(final Context context, final int subId) {
|
||||
final SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
|
||||
subscriptionManager.setDefaultSmsSubId(subId);
|
||||
}
|
||||
|
||||
private void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle phoneAccount) {
|
||||
final TelecomManager telecomManager = TelecomManager.from(this);
|
||||
private void setDefaultCallsSubId(final int subId) {
|
||||
final PhoneAccountHandle phoneAccount = subscriptionIdToPhoneAccountHandle(subId);
|
||||
final TelecomManager telecomManager = getSystemService(TelecomManager.class);
|
||||
telecomManager.setUserSelectedOutgoingPhoneAccount(phoneAccount);
|
||||
}
|
||||
|
||||
private PhoneAccountHandle subscriptionIdToPhoneAccountHandle(final int subId) {
|
||||
final TelecomManager telecomManager = TelecomManager.from(this);
|
||||
final TelephonyManager telephonyManager = TelephonyManager.from(this);
|
||||
final Iterator<PhoneAccountHandle> phoneAccounts =
|
||||
telecomManager.getCallCapablePhoneAccounts().listIterator();
|
||||
private void setDefaultSmsSubId(final int subId) {
|
||||
final SubscriptionManager subscriptionManager = getSystemService(SubscriptionManager.class);
|
||||
subscriptionManager.setDefaultSmsSubId(subId);
|
||||
}
|
||||
|
||||
while (phoneAccounts.hasNext()) {
|
||||
final PhoneAccountHandle phoneAccountHandle = phoneAccounts.next();
|
||||
final PhoneAccount phoneAccount = telecomManager.getPhoneAccount(phoneAccountHandle);
|
||||
private void setPreferredSim(final int subId) {
|
||||
setDefaultDataSubId(subId);
|
||||
setDefaultSmsSubId(subId);
|
||||
setDefaultCallsSubId(subId);
|
||||
}
|
||||
|
||||
private PhoneAccountHandle subscriptionIdToPhoneAccountHandle(final int subId) {
|
||||
final TelecomManager telecomManager = getSystemService(TelecomManager.class);
|
||||
final TelephonyManager telephonyManager = getSystemService(TelephonyManager.class);
|
||||
|
||||
for (PhoneAccountHandle handle : telecomManager.getCallCapablePhoneAccounts()) {
|
||||
final PhoneAccount phoneAccount = telecomManager.getPhoneAccount(handle);
|
||||
if (subId == telephonyManager.getSubIdForPhoneAccount(phoneAccount)) {
|
||||
return phoneAccountHandle;
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Dialog createDialog(final Context context, final int id) {
|
||||
final ArrayList<String> list = new ArrayList<String>();
|
||||
final SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
|
||||
final List<SubscriptionInfo> subInfoList =
|
||||
subscriptionManager.getActiveSubscriptionInfoList(true);
|
||||
final int selectableSubInfoLength = subInfoList == null ? 0 : subInfoList.size();
|
||||
|
||||
final DialogInterface.OnClickListener selectionListener =
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int value) {
|
||||
|
||||
final SubscriptionInfo sir;
|
||||
|
||||
switch (id) {
|
||||
case DATA_PICK:
|
||||
sir = subInfoList.get(value);
|
||||
setDefaultDataSubId(context, sir.getSubscriptionId());
|
||||
break;
|
||||
case CALLS_PICK:
|
||||
final TelecomManager telecomManager =
|
||||
TelecomManager.from(context);
|
||||
final List<PhoneAccountHandle> phoneAccountsList =
|
||||
telecomManager.getCallCapablePhoneAccounts();
|
||||
setUserSelectedOutgoingPhoneAccount(
|
||||
value < 1 ? null : phoneAccountsList.get(value - 1));
|
||||
break;
|
||||
case SMS_PICK:
|
||||
sir = subInfoList.get(value);
|
||||
setDefaultSmsSubId(context, sir.getSubscriptionId());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid dialog type "
|
||||
+ id + " in SIM dialog.");
|
||||
}
|
||||
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
Dialog.OnKeyListener keyListener = new Dialog.OnKeyListener() {
|
||||
@Override
|
||||
public boolean onKey(DialogInterface arg0, int keyCode,
|
||||
KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
finish();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
ArrayList<SubscriptionInfo> callsSubInfoList = new ArrayList<SubscriptionInfo>();
|
||||
if (id == CALLS_PICK) {
|
||||
final TelecomManager telecomManager = TelecomManager.from(context);
|
||||
final TelephonyManager telephonyManager = TelephonyManager.from(context);
|
||||
final Iterator<PhoneAccountHandle> phoneAccounts =
|
||||
telecomManager.getCallCapablePhoneAccounts().listIterator();
|
||||
|
||||
list.add(getResources().getString(R.string.sim_calls_ask_first_prefs_title));
|
||||
callsSubInfoList.add(null);
|
||||
while (phoneAccounts.hasNext()) {
|
||||
final PhoneAccount phoneAccount =
|
||||
telecomManager.getPhoneAccount(phoneAccounts.next());
|
||||
list.add((String)phoneAccount.getLabel());
|
||||
int subId = telephonyManager.getSubIdForPhoneAccount(phoneAccount);
|
||||
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
||||
final SubscriptionInfo sir = SubscriptionManager.from(context)
|
||||
.getActiveSubscriptionInfo(subId);
|
||||
callsSubInfoList.add(sir);
|
||||
} else {
|
||||
callsSubInfoList.add(null);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < selectableSubInfoLength; ++i) {
|
||||
final SubscriptionInfo sir = subInfoList.get(i);
|
||||
CharSequence displayName = sir.getDisplayName();
|
||||
if (displayName == null) {
|
||||
displayName = "";
|
||||
}
|
||||
list.add(displayName.toString());
|
||||
}
|
||||
}
|
||||
|
||||
String[] arr = list.toArray(new String[0]);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
|
||||
ListAdapter adapter = new SelectAccountListAdapter(
|
||||
id == CALLS_PICK ? callsSubInfoList : subInfoList,
|
||||
builder.getContext(),
|
||||
R.layout.select_account_list_item,
|
||||
arr, id);
|
||||
|
||||
switch (id) {
|
||||
case DATA_PICK:
|
||||
builder.setTitle(R.string.select_sim_for_data);
|
||||
break;
|
||||
case CALLS_PICK:
|
||||
builder.setTitle(R.string.select_sim_for_calls);
|
||||
break;
|
||||
case SMS_PICK:
|
||||
builder.setTitle(R.string.select_sim_for_sms);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid dialog type "
|
||||
+ id + " in SIM dialog.");
|
||||
}
|
||||
|
||||
Dialog dialog = builder.setAdapter(adapter, selectionListener).create();
|
||||
dialog.setOnKeyListener(keyListener);
|
||||
|
||||
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialogInterface) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
return dialog;
|
||||
|
||||
}
|
||||
|
||||
private class SelectAccountListAdapter extends ArrayAdapter<String> {
|
||||
private Context mContext;
|
||||
private int mResId;
|
||||
private int mDialogId;
|
||||
private final float OPACITY = 0.54f;
|
||||
private List<SubscriptionInfo> mSubInfoList;
|
||||
|
||||
public SelectAccountListAdapter(List<SubscriptionInfo> subInfoList,
|
||||
Context context, int resource, String[] arr, int dialogId) {
|
||||
super(context, resource, arr);
|
||||
mContext = context;
|
||||
mResId = resource;
|
||||
mDialogId = dialogId;
|
||||
mSubInfoList = subInfoList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
LayoutInflater inflater = (LayoutInflater)
|
||||
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View rowView;
|
||||
final ViewHolder holder;
|
||||
|
||||
if (convertView == null) {
|
||||
// Cache views for faster scrolling
|
||||
rowView = inflater.inflate(mResId, null);
|
||||
holder = new ViewHolder();
|
||||
holder.title = (TextView) rowView.findViewById(R.id.title);
|
||||
holder.summary = (TextView) rowView.findViewById(R.id.summary);
|
||||
holder.icon = (ImageView) rowView.findViewById(R.id.icon);
|
||||
rowView.setTag(holder);
|
||||
} else {
|
||||
rowView = convertView;
|
||||
holder = (ViewHolder) rowView.getTag();
|
||||
}
|
||||
|
||||
final SubscriptionInfo sir = mSubInfoList.get(position);
|
||||
if (sir == null) {
|
||||
holder.title.setText(getItem(position));
|
||||
holder.summary.setText("");
|
||||
holder.icon.setImageDrawable(getResources()
|
||||
.getDrawable(R.drawable.ic_live_help));
|
||||
holder.icon.setAlpha(OPACITY);
|
||||
} else {
|
||||
holder.title.setText(sir.getDisplayName());
|
||||
holder.summary.setText(sir.getNumber());
|
||||
holder.icon.setImageBitmap(sir.createIconBitmap(mContext));
|
||||
}
|
||||
return rowView;
|
||||
}
|
||||
|
||||
private class ViewHolder {
|
||||
TextView title;
|
||||
TextView summary;
|
||||
ImageView icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
57
src/com/android/settings/sim/SimDialogFragment.java
Normal file
57
src/com/android/settings/sim/SimDialogFragment.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.sim;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
/** Common functionality for showing a dialog in SimDialogActivity. */
|
||||
public abstract class SimDialogFragment extends DialogFragment {
|
||||
private static final String TAG = "SimDialogFragment";
|
||||
|
||||
private static final String KEY_TITLE_ID = "title_id";
|
||||
private static final String KEY_DIALOG_TYPE = "dialog_type";
|
||||
|
||||
protected static Bundle initArguments(int dialogType, int titleResId) {
|
||||
final Bundle args = new Bundle();
|
||||
args.putInt(KEY_DIALOG_TYPE, dialogType);
|
||||
args.putInt(KEY_TITLE_ID, titleResId);
|
||||
return args;
|
||||
}
|
||||
|
||||
public int getDialogType() {
|
||||
return getArguments().getInt(KEY_DIALOG_TYPE);
|
||||
}
|
||||
|
||||
public int getTitleResId() {
|
||||
return getArguments().getInt(KEY_TITLE_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(@NonNull DialogInterface dialog) {
|
||||
super.onDismiss(dialog);
|
||||
final SimDialogActivity activity = (SimDialogActivity) getActivity();
|
||||
if (activity != null && !activity.isFinishing()) {
|
||||
activity.onFragmentDismissed(this);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void updateDialog();
|
||||
}
|
||||
183
src/com/android/settings/sim/SimListDialogFragment.java
Normal file
183
src/com/android/settings/sim/SimListDialogFragment.java
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.sim;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Shows a dialog consisting of a list of SIMs (aka subscriptions), possibly including an additional
|
||||
* entry indicating "ask me every time".
|
||||
*/
|
||||
public class SimListDialogFragment extends SimDialogFragment implements
|
||||
DialogInterface.OnClickListener {
|
||||
protected static final String KEY_INCLUDE_ASK_EVERY_TIME = "include_ask_every_time";
|
||||
|
||||
protected SelectSubscriptionAdapter mAdapter;
|
||||
@VisibleForTesting
|
||||
List<SubscriptionInfo> mSubscriptions;
|
||||
|
||||
public static SimListDialogFragment newInstance(int dialogType, int titleResId,
|
||||
boolean includeAskEveryTime) {
|
||||
final SimListDialogFragment fragment = new SimListDialogFragment();
|
||||
final Bundle args = initArguments(dialogType, titleResId);
|
||||
args.putBoolean(KEY_INCLUDE_ASK_EVERY_TIME, includeAskEveryTime);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
mSubscriptions = new ArrayList<>();
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
builder.setTitle(getTitleResId());
|
||||
|
||||
mAdapter = new SelectSubscriptionAdapter(builder.getContext(), mSubscriptions);
|
||||
|
||||
setAdapter(builder);
|
||||
final Dialog dialog = builder.create();
|
||||
updateDialog();
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int selectionIndex) {
|
||||
if (selectionIndex >= 0 && selectionIndex < mSubscriptions.size()) {
|
||||
int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
final SubscriptionInfo subscription = mSubscriptions.get(selectionIndex);
|
||||
if (subscription != null) {
|
||||
subId = subscription.getSubscriptionId();
|
||||
}
|
||||
final SimDialogActivity activity = (SimDialogActivity) getActivity();
|
||||
activity.onSubscriptionSelected(getDialogType(), subId);
|
||||
}
|
||||
}
|
||||
|
||||
protected List<SubscriptionInfo> getCurrentSubscriptions() {
|
||||
final SubscriptionManager manager = getContext().getSystemService(
|
||||
SubscriptionManager.class);
|
||||
return manager.getActiveSubscriptionInfoList(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDialog() {
|
||||
List<SubscriptionInfo> currentSubscriptions = getCurrentSubscriptions();
|
||||
if (currentSubscriptions == null) {
|
||||
dismiss();
|
||||
return;
|
||||
}
|
||||
if (getArguments().getBoolean(KEY_INCLUDE_ASK_EVERY_TIME)) {
|
||||
final List<SubscriptionInfo> tmp = new ArrayList<>(currentSubscriptions.size() + 1);
|
||||
tmp.add(null);
|
||||
tmp.addAll(currentSubscriptions);
|
||||
currentSubscriptions = tmp;
|
||||
}
|
||||
if (currentSubscriptions.equals(mSubscriptions)) {
|
||||
return;
|
||||
}
|
||||
mSubscriptions.clear();
|
||||
mSubscriptions.addAll(currentSubscriptions);
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setAdapter(AlertDialog.Builder builder) {
|
||||
builder.setAdapter(mAdapter, this);
|
||||
}
|
||||
|
||||
private static class SelectSubscriptionAdapter extends BaseAdapter {
|
||||
private Context mContext;
|
||||
private LayoutInflater mInflater;
|
||||
List<SubscriptionInfo> mSubscriptions;
|
||||
|
||||
public SelectSubscriptionAdapter(Context context, List<SubscriptionInfo> subscriptions) {
|
||||
mSubscriptions = subscriptions;
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mSubscriptions.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubscriptionInfo getItem(int position) {
|
||||
return mSubscriptions.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
final SubscriptionInfo info = mSubscriptions.get(position);
|
||||
if (info == null) {
|
||||
return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
}
|
||||
return info.getSubscriptionId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
if (mInflater == null) {
|
||||
mInflater = LayoutInflater.from(parent.getContext());
|
||||
}
|
||||
convertView = mInflater.inflate(R.layout.select_account_list_item, parent, false);
|
||||
}
|
||||
final SubscriptionInfo sub = getItem(position);
|
||||
|
||||
final TextView title = convertView.findViewById(R.id.title);
|
||||
final TextView summary = convertView.findViewById(R.id.summary);
|
||||
final ImageView icon = convertView.findViewById(R.id.icon);
|
||||
|
||||
if (sub == null) {
|
||||
title.setText(R.string.sim_calls_ask_first_prefs_title);
|
||||
summary.setText("");
|
||||
icon.setImageDrawable(mContext.getDrawable(R.drawable.ic_help));
|
||||
icon.setImageTintList(
|
||||
Utils.getColorAttr(mContext, android.R.attr.textColorSecondary));
|
||||
} else {
|
||||
title.setText(sub.getDisplayName());
|
||||
summary.setText(sub.getNumber());
|
||||
icon.setImageBitmap(sub.createIconBitmap(mContext));
|
||||
|
||||
}
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,6 @@ package com.android.settings.slices;
|
||||
import static android.provider.SettingsSlicesContract.KEY_LOCATION;
|
||||
import static android.provider.SettingsSlicesContract.KEY_WIFI;
|
||||
|
||||
import static com.android.settings.notification.ZenModeSoundSettingsPreferenceController.ZEN_MODE_KEY;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.net.Uri;
|
||||
import android.provider.SettingsSlicesContract;
|
||||
@@ -43,6 +41,7 @@ import com.android.settings.location.LocationSlice;
|
||||
import com.android.settings.media.MediaOutputIndicatorSlice;
|
||||
import com.android.settings.media.MediaOutputSlice;
|
||||
import com.android.settings.network.telephony.MobileDataSlice;
|
||||
import com.android.settings.notification.ZenModeButtonPreferenceController;
|
||||
import com.android.settings.wifi.calling.WifiCallingSliceHelper;
|
||||
import com.android.settings.wifi.slice.ContextualWifiSlice;
|
||||
import com.android.settings.wifi.slice.WifiSlice;
|
||||
@@ -298,7 +297,7 @@ public class CustomSliceRegistry {
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||
.appendPath(ZEN_MODE_KEY)
|
||||
.appendPath(ZenModeButtonPreferenceController.KEY)
|
||||
.build();
|
||||
|
||||
/**
|
||||
|
||||
@@ -164,11 +164,12 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
|
||||
}
|
||||
|
||||
final SliderPreferenceController sliderController = (SliderPreferenceController) controller;
|
||||
final int maxSteps = sliderController.getMaxSteps();
|
||||
if (newPosition < 0 || newPosition > maxSteps) {
|
||||
final int minValue = sliderController.getMin();
|
||||
final int maxValue = sliderController.getMax();
|
||||
if (newPosition < minValue || newPosition > maxValue) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid position passed to Slider controller. Expected between 0 and "
|
||||
+ maxSteps + " but found " + newPosition);
|
||||
"Invalid position passed to Slider controller. Expected between " + minValue
|
||||
+ " and " + maxValue + " but found " + newPosition);
|
||||
}
|
||||
|
||||
sliderController.setSliderPosition(newPosition);
|
||||
|
||||
@@ -326,7 +326,8 @@ public class SliceBuilderUtils {
|
||||
.setTitle(sliceData.getTitle())
|
||||
.setSubtitle(subtitleText)
|
||||
.setPrimaryAction(primaryAction)
|
||||
.setMax(sliderController.getMaxSteps())
|
||||
.setMax(sliderController.getMax())
|
||||
.setMin(sliderController.getMin())
|
||||
.setValue(sliderController.getSliderPosition())
|
||||
.setInputAction(actionIntent))
|
||||
.setKeywords(keywords)
|
||||
|
||||
@@ -93,7 +93,7 @@ public class SeekBarPreference extends RestrictedPreference
|
||||
|
||||
@Override
|
||||
public boolean isSelectable() {
|
||||
return false;
|
||||
return isDisabledByAdmin();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
101
src/com/android/settings/widget/TintDrawable.java
Normal file
101
src/com/android/settings/widget/TintDrawable.java
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Resources.Theme;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.DrawableWrapper;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A Drawable that tints a contained Drawable, overriding the existing tint specified in the
|
||||
* underlying drawable. This class should only be used in XML.
|
||||
*
|
||||
* @attr ref android.R.styleable#DrawableWrapper_drawable
|
||||
* @attr ref R.styleable#TintDrawable_tint
|
||||
*/
|
||||
public class TintDrawable extends DrawableWrapper {
|
||||
private ColorStateList mTint;
|
||||
private int[] mThemeAttrs;
|
||||
|
||||
/** No-arg constructor used by drawable inflation. */
|
||||
public TintDrawable() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
|
||||
@NonNull AttributeSet attrs, @Nullable Theme theme)
|
||||
throws XmlPullParserException, IOException {
|
||||
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.TintDrawable);
|
||||
|
||||
super.inflate(r, parser, attrs, theme);
|
||||
|
||||
mThemeAttrs = a.extractThemeAttrs();
|
||||
updateStateFromTypedArray(a);
|
||||
a.recycle();
|
||||
|
||||
applyTint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyTheme(Theme t) {
|
||||
super.applyTheme(t);
|
||||
|
||||
if (mThemeAttrs != null) {
|
||||
final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.TintDrawable);
|
||||
updateStateFromTypedArray(a);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
// Ensure tint is reapplied after applying the theme to ensure this drawables'
|
||||
// tint overrides the underlying drawables' tint.
|
||||
applyTint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canApplyTheme() {
|
||||
return (mThemeAttrs != null && mThemeAttrs.length > 0) || super.canApplyTheme();
|
||||
}
|
||||
|
||||
private void updateStateFromTypedArray(@NonNull TypedArray a) {
|
||||
if (a.hasValue(R.styleable.TintDrawable_android_drawable)) {
|
||||
setDrawable(a.getDrawable(R.styleable.TintDrawable_android_drawable));
|
||||
}
|
||||
if (a.hasValue(R.styleable.TintDrawable_android_tint)) {
|
||||
mTint = a.getColorStateList(R.styleable.TintDrawable_android_tint);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyTint() {
|
||||
if (getDrawable() != null && mTint != null) {
|
||||
getDrawable().mutate().setTintList(mTint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.settings.wifi;
|
||||
|
||||
import android.annotation.StyleRes;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
@@ -64,11 +65,21 @@ public class WifiDialog extends AlertDialog implements WifiConfigUiBase,
|
||||
public static WifiDialog createModal(Context context, WifiDialogListener listener,
|
||||
AccessPoint accessPoint, int mode) {
|
||||
return new WifiDialog(context, listener, accessPoint, mode, 0 /* style */,
|
||||
mode == WifiConfigUiBase.MODE_VIEW /* hideSubmitButton*/);
|
||||
mode == WifiConfigUiBase.MODE_VIEW /* hideSubmitButton */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a WifiDialog with customized style. It displays as a dialog above the current
|
||||
* view.
|
||||
*/
|
||||
public static WifiDialog createModal(Context context, WifiDialogListener listener,
|
||||
AccessPoint accessPoint, int mode, @StyleRes int style) {
|
||||
return new WifiDialog(context, listener, accessPoint, mode, style,
|
||||
mode == WifiConfigUiBase.MODE_VIEW /* hideSubmitButton */);
|
||||
}
|
||||
|
||||
/* package */ WifiDialog(Context context, WifiDialogListener listener, AccessPoint accessPoint,
|
||||
int mode, int style, boolean hideSubmitButton) {
|
||||
int mode, @StyleRes int style, boolean hideSubmitButton) {
|
||||
super(context, style);
|
||||
mMode = mode;
|
||||
mListener = listener;
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SetupWizardUtils;
|
||||
import com.android.settings.wifi.dpp.WifiDppUtils;
|
||||
import com.android.settingslib.wifi.AccessPoint;
|
||||
@@ -74,8 +75,13 @@ public class WifiDialogActivity extends Activity implements WifiDialog.WifiDialo
|
||||
accessPoint = new AccessPoint(this, accessPointState);
|
||||
}
|
||||
|
||||
mDialog = WifiDialog.createModal(
|
||||
this, this, accessPoint, WifiConfigUiBase.MODE_CONNECT);
|
||||
if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
|
||||
mDialog = WifiDialog.createModal(this, this, accessPoint,
|
||||
WifiConfigUiBase.MODE_CONNECT, R.style.SuwAlertDialogThemeCompat_Light);
|
||||
} else {
|
||||
mDialog = WifiDialog.createModal(
|
||||
this, this, accessPoint, WifiConfigUiBase.MODE_CONNECT);
|
||||
}
|
||||
mDialog.show();
|
||||
mDialog.setOnDismissListener(this);
|
||||
}
|
||||
|
||||
@@ -404,9 +404,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
|
||||
.setButton3Enabled(true)
|
||||
.setButton4Text(R.string.share)
|
||||
.setButton4Icon(R.drawable.ic_qrcode_24dp)
|
||||
.setButton4OnClickListener(view -> shareNetwork())
|
||||
.setButton4Visible(
|
||||
WifiDppUtils.isSupportConfiguratorQrCodeGenerator(mContext, mAccessPoint));
|
||||
.setButton4OnClickListener(view -> shareNetwork());
|
||||
|
||||
mSignalStrengthPref = screen.findPreference(KEY_SIGNAL_STRENGTH_PREF);
|
||||
mTxLinkSpeedPref = screen.findPreference(KEY_TX_LINK_SPEED);
|
||||
@@ -739,14 +737,19 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
|
||||
mButtonsPref.setButton1Text(
|
||||
mIsEphemeral ? R.string.wifi_disconnect_button_text : R.string.forget);
|
||||
|
||||
mButtonsPref.setButton1Visible(canForgetNetwork());
|
||||
mButtonsPref.setButton2Visible(canSignIntoNetwork());
|
||||
mButtonsPref.setButton3Visible(canConnectNetwork());
|
||||
mButtonsPref.setButton4Visible(canShareNetwork());
|
||||
mButtonsPref.setVisible(canSignIntoNetwork()
|
||||
|| canForgetNetwork()
|
||||
|| canShareNetwork()
|
||||
|| canConnectNetwork());
|
||||
boolean canForgetNetwork = canForgetNetwork();
|
||||
boolean canSignIntoNetwork = canSignIntoNetwork();
|
||||
boolean canConnectNetwork = canConnectNetwork();
|
||||
boolean canShareNetwork = canShareNetwork();
|
||||
|
||||
mButtonsPref.setButton1Visible(canForgetNetwork);
|
||||
mButtonsPref.setButton2Visible(canSignIntoNetwork);
|
||||
mButtonsPref.setButton3Visible(canConnectNetwork);
|
||||
mButtonsPref.setButton4Visible(canShareNetwork);
|
||||
mButtonsPref.setVisible(canForgetNetwork
|
||||
|| canSignIntoNetwork
|
||||
|| canConnectNetwork
|
||||
|| canShareNetwork);
|
||||
}
|
||||
|
||||
private boolean canConnectNetwork() {
|
||||
@@ -843,7 +846,8 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
|
||||
* Returns whether the user can share the network represented by this preference with QR code.
|
||||
*/
|
||||
private boolean canShareNetwork() {
|
||||
return mAccessPoint.getConfig() != null;
|
||||
return mAccessPoint.getConfig() != null &&
|
||||
WifiDppUtils.isSupportConfiguratorQrCodeGenerator(mContext, mAccessPoint);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -345,6 +345,9 @@ public class WifiDppUtils {
|
||||
*/
|
||||
public static boolean isSupportConfiguratorQrCodeScanner(Context context,
|
||||
AccessPoint accessPoint) {
|
||||
if (accessPoint.isPasspoint()) {
|
||||
return false;
|
||||
}
|
||||
return isSupportWifiDpp(context, accessPoint.getSecurity());
|
||||
}
|
||||
|
||||
@@ -356,6 +359,9 @@ public class WifiDppUtils {
|
||||
*/
|
||||
public static boolean isSupportConfiguratorQrCodeGenerator(Context context,
|
||||
AccessPoint accessPoint) {
|
||||
if (accessPoint.isPasspoint()) {
|
||||
return false;
|
||||
}
|
||||
return isSupportZxing(context, accessPoint.getSecurity());
|
||||
}
|
||||
|
||||
|
||||
@@ -154,19 +154,6 @@ public class AccessibilitySettingsTest {
|
||||
assertThat(preference.getSummary()).isEqualTo(mContext.getResources().getString(resId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDarkUIModePreferenceSummary_shouldUpdateSummary() {
|
||||
final Preference darkUIModePreference = new Preference(mContext);
|
||||
final DarkUIPreferenceController mController;
|
||||
doReturn(darkUIModePreference).when(mSettings).findPreference(
|
||||
DARK_UI_MODE_PREFERENCE);
|
||||
mController = new DarkUIPreferenceController(mContext, DARK_UI_MODE_PREFERENCE);
|
||||
final String darkUIModeDescription = modeToDescription(mUiModeManager.getNightMode());
|
||||
darkUIModePreference.setSummary(mController.getSummary());
|
||||
|
||||
assertThat(darkUIModePreference.getSummary()).isEqualTo(darkUIModeDescription);
|
||||
}
|
||||
|
||||
private String modeToDescription(int mode) {
|
||||
String[] values = mContext.getResources().getStringArray(R.array.dark_ui_mode_entries);
|
||||
switch (mode) {
|
||||
|
||||
@@ -31,8 +31,10 @@ import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import static com.android.settings.backup.UserBackupSettingsActivityTest.ShadowBackupSettingsHelper;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowPrivacySettingsUtils.class})
|
||||
@Config(shadows = {ShadowPrivacySettingsUtils.class, ShadowBackupSettingsHelper.class})
|
||||
public class BackupInactivePreferenceControllerTest {
|
||||
private Context mContext;
|
||||
private BackupInactivePreferenceController mController;
|
||||
@@ -48,18 +50,32 @@ public class BackupInactivePreferenceControllerTest {
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowPrivacySettingsUtils.reset();
|
||||
ShadowBackupSettingsHelper.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_isnotInvisibleKey_shouldBeAvailable() {
|
||||
public void getAvailabilityStatus_isnotInvisibleKey_showBackup_shouldBeAvailable() {
|
||||
ShadowPrivacySettingsUtils.setIsInvisibleKey(false);
|
||||
ShadowBackupSettingsHelper.showBackupSettingsForUser = true;
|
||||
|
||||
assertThat(mController.getAvailabilityStatus())
|
||||
.isEqualTo(BasePreferenceController.AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_isnotInvisibleKey_dontShowBackup_shouldBeUnsearchable() {
|
||||
ShadowPrivacySettingsUtils.setIsInvisibleKey(false);
|
||||
ShadowBackupSettingsHelper.showBackupSettingsForUser = false;
|
||||
|
||||
assertThat(mController.getAvailabilityStatus())
|
||||
.isEqualTo(BasePreferenceController.AVAILABLE_UNSEARCHABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_isInvisibleKey_shouldBeDisabledUnsupported() {
|
||||
ShadowPrivacySettingsUtils.setIsInvisibleKey(true);
|
||||
ShadowBackupSettingsHelper.showBackupSettingsForUser = true;
|
||||
|
||||
assertThat(mController.getAvailabilityStatus())
|
||||
.isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import android.app.Application;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
@@ -53,8 +52,7 @@ import org.robolectric.annotation.Resetter;
|
||||
import org.robolectric.shadows.ShadowPackageManager;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {UserBackupSettingsActivityTest.ShadowBackupSettingsHelper.class,
|
||||
UserBackupSettingsActivityTest.ShadowUserHandle.class})
|
||||
@Config(shadows = {UserBackupSettingsActivityTest.ShadowBackupSettingsHelper.class})
|
||||
public class UserBackupSettingsActivityTest {
|
||||
private ActivityController<UserBackupSettingsActivity> mActivityController;
|
||||
private UserBackupSettingsActivity mActivity;
|
||||
@@ -85,7 +83,7 @@ public class UserBackupSettingsActivityTest {
|
||||
|
||||
@After
|
||||
public void resetShadows() {
|
||||
ShadowUserHandle.reset();
|
||||
ShadowBackupSettingsHelper.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -125,7 +123,9 @@ public class UserBackupSettingsActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNonIndexableKeys_SystemUser() {
|
||||
public void getNonIndexableKeys_whenShowBackupSettings() {
|
||||
ShadowBackupSettingsHelper.showBackupSettingsForUser = true;
|
||||
|
||||
assertThat(UserBackupSettingsActivity.SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(
|
||||
mApplication, true)).isNotEmpty();
|
||||
assertThat(UserBackupSettingsActivity.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(
|
||||
@@ -133,17 +133,24 @@ public class UserBackupSettingsActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNonIndexableKeys_NonSystemUser() {
|
||||
ShadowUserHandle.setUid(1); // Non-SYSTEM user.
|
||||
public void getNonIndexableKeys_whenDontShowBackupSettings() {
|
||||
ShadowBackupSettingsHelper.showBackupSettingsForUser = false;
|
||||
|
||||
assertThat(UserBackupSettingsActivity.SEARCH_INDEX_DATA_PROVIDER.getRawDataToIndex(
|
||||
mApplication, true)).isNotEmpty();
|
||||
assertThat(UserBackupSettingsActivity.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(
|
||||
mApplication)).isEmpty();
|
||||
mApplication)).contains("Backup");
|
||||
}
|
||||
|
||||
@Implements(BackupSettingsHelper.class)
|
||||
public static class ShadowBackupSettingsHelper {
|
||||
static boolean showBackupSettingsForUser = true;
|
||||
|
||||
@Implementation
|
||||
public boolean showBackupSettingsForUser() {
|
||||
return showBackupSettingsForUser;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected Intent getIntentForBackupSettings() {
|
||||
return mIntent;
|
||||
@@ -153,24 +160,10 @@ public class UserBackupSettingsActivityTest {
|
||||
protected boolean isBackupProvidedByManufacturer() {
|
||||
return mIsBackupProvidedByOEM;
|
||||
}
|
||||
}
|
||||
|
||||
@Implements(UserHandle.class)
|
||||
public static class ShadowUserHandle {
|
||||
private static int sUid = 0; // SYSTEM by default
|
||||
|
||||
public static void setUid(int uid) {
|
||||
sUid = uid;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static int myUserId() {
|
||||
return sUid;
|
||||
}
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sUid = 0;
|
||||
showBackupSettingsForUser = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,8 @@ public class SettingsSliderPreferenceControllerTest {
|
||||
"key");
|
||||
|
||||
mPreference.setContinuousUpdates(true);
|
||||
mPreference.setMax(mSliderController.getMaxSteps());
|
||||
mPreference.setMin(mSliderController.getMin());
|
||||
mPreference.setMax(mSliderController.getMax());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -89,10 +90,15 @@ public class SettingsSliderPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSteps() {
|
||||
public int getMax() {
|
||||
return MAX_STEPS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMin() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
|
||||
@@ -88,10 +88,15 @@ public class SliderPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSteps() {
|
||||
public int getMax() {
|
||||
return MAX_STEPS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMin() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
|
||||
@@ -18,22 +18,32 @@ package com.android.settings.datausage;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkTemplate;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.widget.LoadingViewController;
|
||||
import com.android.settingslib.AppItem;
|
||||
import com.android.settingslib.NetworkPolicyEditor;
|
||||
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
|
||||
@@ -45,15 +55,14 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.android.controller.ActivityController;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class DataUsageListTest {
|
||||
|
||||
@@ -61,18 +70,21 @@ public class DataUsageListTest {
|
||||
private CellDataPreference.DataStateListener mListener;
|
||||
@Mock
|
||||
private TemplatePreference.NetworkServices mNetworkServices;
|
||||
@Mock
|
||||
private Context mContext;
|
||||
|
||||
private Activity mActivity;
|
||||
private DataUsageList mDataUsageList;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
FakeFeatureFactory.setupForTest();
|
||||
final ActivityController<Activity> mActivityController =
|
||||
Robolectric.buildActivity(Activity.class);
|
||||
mActivity = spy(mActivityController.get());
|
||||
mNetworkServices.mPolicyEditor = mock(NetworkPolicyEditor.class);
|
||||
mDataUsageList = spy(DataUsageList.class);
|
||||
|
||||
doReturn(mContext).when(mDataUsageList).getContext();
|
||||
doReturn(mActivity).when(mDataUsageList).getContext();
|
||||
ReflectionHelpers.setField(mDataUsageList, "mDataStateListener", mListener);
|
||||
ReflectionHelpers.setField(mDataUsageList, "services", mNetworkServices);
|
||||
}
|
||||
@@ -86,11 +98,11 @@ public class DataUsageListTest {
|
||||
|
||||
mDataUsageList.onResume();
|
||||
|
||||
verify(mListener).setListener(true, mDataUsageList.mSubId, mContext);
|
||||
verify(mListener).setListener(true, mDataUsageList.mSubId, mActivity);
|
||||
|
||||
mDataUsageList.onPause();
|
||||
|
||||
verify(mListener).setListener(false, mDataUsageList.mSubId, mContext);
|
||||
verify(mListener).setListener(false, mDataUsageList.mSubId, mActivity);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -140,7 +152,7 @@ public class DataUsageListTest {
|
||||
final List<NetworkCycleChartData> data = new ArrayList<>();
|
||||
final NetworkCycleChartData.Builder builder = new NetworkCycleChartData.Builder();
|
||||
builder.setStartTime(startTime)
|
||||
.setEndTime(endTime);
|
||||
.setEndTime(endTime);
|
||||
data.add(builder.build());
|
||||
ReflectionHelpers.setField(mDataUsageList, "mCycleData", data);
|
||||
final Spinner spinner = mock(Spinner.class);
|
||||
@@ -150,14 +162,58 @@ public class DataUsageListTest {
|
||||
|
||||
mDataUsageList.startAppDataUsage(new AppItem());
|
||||
|
||||
verify(mContext).startActivity(intent.capture());
|
||||
verify(mActivity).startActivity(intent.capture());
|
||||
final Bundle arguments =
|
||||
intent.getValue().getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
|
||||
intent.getValue().getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
|
||||
assertThat(arguments.getLong(AppDataUsage.ARG_SELECTED_CYCLE)).isEqualTo(endTime);
|
||||
final ArrayList<Long> cycles =
|
||||
(ArrayList) arguments.getSerializable(AppDataUsage.ARG_NETWORK_CYCLES);
|
||||
(ArrayList) arguments.getSerializable(AppDataUsage.ARG_NETWORK_CYCLES);
|
||||
assertThat(cycles).hasSize(2);
|
||||
assertThat(cycles.get(0)).isEqualTo(endTime);
|
||||
assertThat(cycles.get(1)).isEqualTo(startTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onViewCreated_shouldHideCycleSpinner() {
|
||||
final View view = new View(mActivity);
|
||||
final View header = getHeader();
|
||||
final Spinner spinner = getSpinner(header);
|
||||
spinner.setVisibility(View.VISIBLE);
|
||||
doReturn(header).when(mDataUsageList).setPinnedHeaderView(anyInt());
|
||||
doReturn(view).when(mDataUsageList).getView();
|
||||
|
||||
mDataUsageList.onViewCreated(view, null);
|
||||
|
||||
assertThat(spinner.getVisibility()).isEqualTo(View.GONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onLoadFinished_networkCycleDataCallback_shouldShowCycleSpinner() {
|
||||
final LoadingViewController loadingViewController = mock(LoadingViewController.class);
|
||||
mDataUsageList.mLoadingViewController = loadingViewController;
|
||||
final Spinner spinner = getSpinner(getHeader());
|
||||
spinner.setVisibility(View.INVISIBLE);
|
||||
mDataUsageList.mCycleSpinner = spinner;
|
||||
assertThat(spinner.getVisibility()).isEqualTo(View.INVISIBLE);
|
||||
doNothing().when(mDataUsageList).updatePolicy();
|
||||
|
||||
mDataUsageList.mNetworkCycleDataCallbacks.onLoadFinished(null, null);
|
||||
|
||||
assertThat(spinner.getVisibility()).isEqualTo(View.VISIBLE);
|
||||
}
|
||||
|
||||
private View getHeader() {
|
||||
final View rootView = LayoutInflater.from(mActivity)
|
||||
.inflate(R.layout.preference_list_fragment, null, false);
|
||||
final FrameLayout pinnedHeader = rootView.findViewById(R.id.pinned_header);
|
||||
final View header = mActivity.getLayoutInflater()
|
||||
.inflate(R.layout.apps_filter_spinner, pinnedHeader, false);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
private Spinner getSpinner(View header) {
|
||||
final Spinner spinner = header.findViewById(R.id.filter_spinner);
|
||||
return spinner;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,15 +20,21 @@ import static android.provider.Settings.System.ADAPTIVE_SLEEP;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.RestrictedPreference;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
@@ -42,6 +48,9 @@ public class AdaptiveSleepPreferenceControllerTest {
|
||||
private AdaptiveSleepPreferenceController mController;
|
||||
private ContentResolver mContentResolver;
|
||||
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
@@ -49,6 +58,10 @@ public class AdaptiveSleepPreferenceControllerTest {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mContentResolver = mContext.getContentResolver();
|
||||
mController = new AdaptiveSleepPreferenceController(mContext, PREFERENCE_KEY);
|
||||
|
||||
|
||||
when(mPackageManager.checkPermission(any(), any())).thenReturn(
|
||||
PackageManager.PERMISSION_GRANTED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -114,4 +127,24 @@ public class AdaptiveSleepPreferenceControllerTest {
|
||||
new AdaptiveSleepPreferenceController(mContext, "any_key");
|
||||
assertThat(controller.isSliceable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isChecked_returnsFalseWhenNotSufficientPermissions() {
|
||||
when(mPackageManager.checkPermission(any(), any())).thenReturn(
|
||||
PackageManager.PERMISSION_DENIED);
|
||||
|
||||
mController.setChecked(true);
|
||||
assertThat(mController.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEnabled_returnsFalseWhenNotSufficientPermissions() {
|
||||
when(mPackageManager.checkPermission(any(), any())).thenReturn(
|
||||
PackageManager.PERMISSION_DENIED);
|
||||
|
||||
mController.setChecked(true);
|
||||
final RestrictedPreference mPreference = new RestrictedPreference(mContext);
|
||||
mController.updateState(mPreference);
|
||||
assertThat(mPreference.isEnabled()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.display;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class DarkUIInfoDialogFragmentTest {
|
||||
private DarkUIInfoDialogFragment mFragment;
|
||||
@Mock
|
||||
private DialogInterface dialog;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mFragment = spy(new DarkUIInfoDialogFragment());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dialogDismissedOnConfirmation() {
|
||||
doReturn(RuntimeEnvironment.application).when(mFragment).getContext();
|
||||
SharedPreferences prefs = RuntimeEnvironment.application.getSharedPreferences(
|
||||
DarkUIPreferenceController.DARK_MODE_PREFS,
|
||||
Context.MODE_PRIVATE);
|
||||
assertThat(prefs.getBoolean(DarkUIPreferenceController.PREF_DARK_MODE_DIALOG_SEEN, false))
|
||||
.isFalse();
|
||||
mFragment.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
|
||||
verify(dialog, times(1)).dismiss();
|
||||
assertThat(prefs.getBoolean(DarkUIPreferenceController.PREF_DARK_MODE_DIALOG_SEEN, false))
|
||||
.isTrue();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package com.android.settings.display;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
import androidx.preference.Preference;
|
||||
import com.android.settings.R;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class DarkUISettingsRadioButtonsControllerTest {
|
||||
|
||||
@Mock
|
||||
private UiModeManager mUiModeManager;
|
||||
@Mock
|
||||
private Preference mFooter;
|
||||
private Context mContext;
|
||||
private DarkUISettingsRadioButtonsController mController;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mController = new DarkUISettingsRadioButtonsController(mContext, mFooter);
|
||||
mController.mManager = mUiModeManager;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void footerUpdatesCorrectly() {
|
||||
doReturn(UiModeManager.MODE_NIGHT_YES).when(mUiModeManager).getNightMode();
|
||||
mController.updateFooter();
|
||||
verify(mFooter).setSummary(eq(R.string.dark_ui_settings_dark_summary));
|
||||
|
||||
doReturn(UiModeManager.MODE_NIGHT_NO).when(mUiModeManager).getNightMode();
|
||||
mController.updateFooter();
|
||||
verify(mFooter).setSummary(eq(R.string.dark_ui_settings_light_summary));
|
||||
}
|
||||
|
||||
public int getCurrentMode() {
|
||||
final UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
|
||||
return uiModeManager.getNightMode();
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package com.android.settings.gestures;
|
||||
|
||||
import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
|
||||
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
|
||||
import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@@ -43,6 +47,9 @@ import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class PreventRingingSwitchPreferenceControllerTest {
|
||||
|
||||
private static final int UNKNOWN = -1;
|
||||
|
||||
private Context mContext;
|
||||
private Resources mResources;
|
||||
private PreventRingingSwitchPreferenceController mController;
|
||||
@@ -76,35 +83,88 @@ public class PreventRingingSwitchPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOn_updateState_hushOff() {
|
||||
public void updateState_hushOff_uncheck() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
|
||||
Settings.Secure.VOLUME_HUSH_OFF);
|
||||
VOLUME_HUSH_OFF);
|
||||
|
||||
mController.updateState(mPreference);
|
||||
|
||||
verify(mController.mSwitch, times(1)).setChecked(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOn_updateState_hushVibrate() {
|
||||
public void updateState_hushVibrate_setChecked() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
|
||||
Settings.Secure.VOLUME_HUSH_VIBRATE);
|
||||
VOLUME_HUSH_VIBRATE);
|
||||
|
||||
mController.updateState(mPreference);
|
||||
|
||||
verify(mController.mSwitch, times(1)).setChecked(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOn_updateState_hushMute() {
|
||||
public void updateState_hushMute_setChecked() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
|
||||
Settings.Secure.VOLUME_HUSH_MUTE);
|
||||
VOLUME_HUSH_MUTE);
|
||||
|
||||
mController.updateState(mPreference);
|
||||
|
||||
verify(mController.mSwitch, times(1)).setChecked(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSwitchChanged_wasHushOff_checked_returnHushVibrate() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
|
||||
VOLUME_HUSH_OFF);
|
||||
|
||||
mController.onSwitchChanged(null, true);
|
||||
|
||||
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.VOLUME_HUSH_GESTURE, UNKNOWN)).isEqualTo(VOLUME_HUSH_VIBRATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSwitchChanged_wasHushMute_unchecked_returnHushOff() {
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
|
||||
VOLUME_HUSH_MUTE);
|
||||
|
||||
mController.onSwitchChanged(null, false);
|
||||
|
||||
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.VOLUME_HUSH_GESTURE, UNKNOWN)).isEqualTo(VOLUME_HUSH_OFF);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSwitchChanged_wasHushMute_checked_returnHushMute() {
|
||||
// this is the case for the page open
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
|
||||
VOLUME_HUSH_MUTE);
|
||||
|
||||
mController.onSwitchChanged(null, true);
|
||||
|
||||
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.VOLUME_HUSH_GESTURE, UNKNOWN)).isEqualTo(VOLUME_HUSH_MUTE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSwitchChanged_wasHushVibrate_checked_returnHushVibrate() {
|
||||
// this is the case for the page open
|
||||
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.VOLUME_HUSH_GESTURE,
|
||||
VOLUME_HUSH_VIBRATE);
|
||||
|
||||
mController.onSwitchChanged(null, true);
|
||||
|
||||
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.VOLUME_HUSH_GESTURE, UNKNOWN)).isEqualTo(VOLUME_HUSH_VIBRATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreferenceClickListenerAttached() {
|
||||
PreferenceScreen preferenceScreen = mock(PreferenceScreen.class);
|
||||
LayoutPreference mLayoutPreference = mock(LayoutPreference.class);
|
||||
when(preferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
|
||||
mLayoutPreference);
|
||||
|
||||
mController.displayPreference(preferenceScreen);
|
||||
|
||||
verify(mLayoutPreference, times(1))
|
||||
|
||||
@@ -18,7 +18,11 @@ package com.android.settings.homepage.contextualcards.slices;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.SliceMetadata;
|
||||
@@ -26,11 +30,13 @@ import androidx.slice.SliceProvider;
|
||||
import androidx.slice.widget.SliceLiveData;
|
||||
|
||||
import com.android.internal.os.BatteryStatsHelper;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.fuelgauge.BatteryStatsHelperLoader;
|
||||
import com.android.settings.fuelgauge.batterytip.BatteryTipLoader;
|
||||
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
||||
import com.android.settings.fuelgauge.batterytip.tips.EarlyWarningTip;
|
||||
import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip;
|
||||
import com.android.settings.slices.SliceBackgroundWorker;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -48,6 +54,10 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {
|
||||
BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
|
||||
BatteryFixSliceTest.ShadowBatteryTipLoader.class
|
||||
})
|
||||
public class BatteryFixSliceTest {
|
||||
|
||||
private Context mContext;
|
||||
@@ -66,13 +76,11 @@ public class BatteryFixSliceTest {
|
||||
@After
|
||||
public void tearDown() {
|
||||
ShadowBatteryTipLoader.reset();
|
||||
ShadowSliceBackgroundWorker.reset();
|
||||
ShadowEarlyWarningTip.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {
|
||||
ShadowBatteryStatsHelperLoader.class,
|
||||
ShadowBatteryTipLoader.class
|
||||
})
|
||||
public void updateBatteryTipAvailabilityCache_hasImportantTip_shouldReturnTrue() {
|
||||
final List<BatteryTip> tips = new ArrayList<>();
|
||||
tips.add(new LowBatteryTip(BatteryTip.StateType.INVISIBLE, false, ""));
|
||||
@@ -85,10 +93,6 @@ public class BatteryFixSliceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {
|
||||
ShadowBatteryStatsHelperLoader.class,
|
||||
ShadowBatteryTipLoader.class
|
||||
})
|
||||
public void getSlice_unimportantSlice_shouldSkip() {
|
||||
final List<BatteryTip> tips = new ArrayList<>();
|
||||
tips.add(new LowBatteryTip(BatteryTip.StateType.INVISIBLE, false, ""));
|
||||
@@ -101,6 +105,28 @@ public class BatteryFixSliceTest {
|
||||
assertThat(SliceMetadata.from(mContext, slice).isErrorSlice()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(shadows = {
|
||||
BatteryFixSliceTest.ShadowEarlyWarningTip.class,
|
||||
BatteryFixSliceTest.ShadowSliceBackgroundWorker.class
|
||||
})
|
||||
public void getSlice_hasImportantTip_shouldTintIcon() {
|
||||
final List<BatteryTip> tips = new ArrayList<>();
|
||||
tips.add(new EarlyWarningTip(BatteryTip.StateType.NEW, false));
|
||||
// Create fake cache data
|
||||
ShadowBatteryTipLoader.setBatteryTips(tips);
|
||||
BatteryFixSlice.updateBatteryTipAvailabilityCache(mContext);
|
||||
// Create fake background worker data
|
||||
BatteryFixSlice.BatteryTipWorker batteryTipWorker = mock(
|
||||
BatteryFixSlice.BatteryTipWorker.class);
|
||||
when(batteryTipWorker.getResults()).thenReturn(tips);
|
||||
ShadowSliceBackgroundWorker.setBatteryTipWorkerWorker(batteryTipWorker);
|
||||
|
||||
final Slice slice = mSlice.getSlice();
|
||||
|
||||
assertThat(ShadowEarlyWarningTip.isIconTintColorIdCalled()).isTrue();
|
||||
}
|
||||
|
||||
@Implements(BatteryStatsHelperLoader.class)
|
||||
public static class ShadowBatteryStatsHelperLoader {
|
||||
|
||||
@@ -129,4 +155,45 @@ public class BatteryFixSliceTest {
|
||||
sBatteryTips = tips;
|
||||
}
|
||||
}
|
||||
|
||||
@Implements(SliceBackgroundWorker.class)
|
||||
public static class ShadowSliceBackgroundWorker {
|
||||
|
||||
private static BatteryFixSlice.BatteryTipWorker sBatteryTipWorkerWorker;
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
sBatteryTipWorkerWorker = null;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected static <T extends SliceBackgroundWorker> T getInstance(Uri uri) {
|
||||
return (T) sBatteryTipWorkerWorker;
|
||||
}
|
||||
|
||||
public static void setBatteryTipWorkerWorker(BatteryFixSlice.BatteryTipWorker worker) {
|
||||
sBatteryTipWorkerWorker = worker;
|
||||
}
|
||||
}
|
||||
|
||||
@Implements(EarlyWarningTip.class)
|
||||
public static class ShadowEarlyWarningTip {
|
||||
|
||||
private static boolean mIsGetIconTintColorIdCalled;
|
||||
|
||||
@Resetter
|
||||
public static void reset() {
|
||||
mIsGetIconTintColorIdCalled = false;
|
||||
}
|
||||
|
||||
@Implementation
|
||||
protected int getIconTintColorId() {
|
||||
mIsGetIconTintColorIdCalled = true;
|
||||
return R.color.battery_bad_color_light;
|
||||
}
|
||||
|
||||
public static boolean isIconTintColorIdCalled() {
|
||||
return mIsGetIconTintColorIdCalled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.TelephonyManager;
|
||||
@@ -65,6 +66,8 @@ public class MobileNetworkSummaryControllerTest {
|
||||
private EuiccManager mEuiccManager;
|
||||
@Mock
|
||||
private PreferenceScreen mPreferenceScreen;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
|
||||
private AddPreference mPreference;
|
||||
private Context mContext;
|
||||
@@ -76,6 +79,7 @@ public class MobileNetworkSummaryControllerTest {
|
||||
mContext = spy(Robolectric.setupActivity(Activity.class));
|
||||
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
|
||||
when(mContext.getSystemService(EuiccManager.class)).thenReturn(mEuiccManager);
|
||||
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
|
||||
when(mTelephonyManager.getNetworkCountryIso()).thenReturn("");
|
||||
when(mEuiccManager.isEnabled()).thenReturn(true);
|
||||
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.EUICC_PROVISIONED, 1);
|
||||
@@ -97,9 +101,22 @@ public class MobileNetworkSummaryControllerTest {
|
||||
final ConnectivityManager cm = mock(ConnectivityManager.class);
|
||||
when(cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
|
||||
when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(cm);
|
||||
when(mUserManager.isAdminUser()).thenReturn(true);
|
||||
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_secondaryUser_notAvailable() {
|
||||
final ConnectivityManager cm = mock(ConnectivityManager.class);
|
||||
when(cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true);
|
||||
when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(cm);
|
||||
when(mUserManager.isAdminUser()).thenReturn(false);
|
||||
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getSummary_noSubscriptions_correctSummaryAndClickHandler() {
|
||||
mController.displayPreference(mPreferenceScreen);
|
||||
@@ -282,6 +299,18 @@ public class MobileNetworkSummaryControllerTest {
|
||||
assertThat(captor.getValue()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onResume_noSubscriptionEsimDisabled_isDisabled() {
|
||||
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
|
||||
SubscriptionUtil.setAvailableSubscriptionsForTesting(null);
|
||||
when(mEuiccManager.isEnabled()).thenReturn(false);
|
||||
mController.displayPreference(mPreferenceScreen);
|
||||
|
||||
mController.onResume();
|
||||
|
||||
assertThat(mPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAirplaneModeChanged_oneSubscriptionAirplaneModeGetsTurnedOn_isDisabled() {
|
||||
final SubscriptionInfo sub1 = mock(SubscriptionInfo.class);
|
||||
|
||||
@@ -121,7 +121,12 @@ public class AdjustVolumeRestrictedPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSteps() {
|
||||
public int getMax() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMin() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,12 @@ import android.media.session.MediaSession;
|
||||
import android.media.session.MediaSessionManager;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
@@ -50,9 +52,9 @@ public class RemoteVolumePreferenceControllerTest {
|
||||
private MediaSessionManager mMediaSessionManager;
|
||||
@Mock
|
||||
private MediaController mMediaController;
|
||||
@Mock
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private ISessionController mStub;
|
||||
@Mock
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private ISessionController mStub2;
|
||||
private MediaSession.Token mToken;
|
||||
private MediaSession.Token mToken2;
|
||||
@@ -78,22 +80,30 @@ public class RemoteVolumePreferenceControllerTest {
|
||||
mPlaybackInfo = new MediaController.PlaybackInfo(
|
||||
MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE, 0, MAX_POS, CURRENT_POS, null);
|
||||
when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
|
||||
when(mMediaController.getSessionToken()).thenReturn(mToken);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_containRemoteMedia_returnTrue() {
|
||||
public void getActiveRemoteToken_containRemoteMedia_returnToken() {
|
||||
when(mMediaController.getPlaybackInfo()).thenReturn(
|
||||
new MediaController.PlaybackInfo(MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
|
||||
0, 0, 0, null));
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
assertThat(mController.getActiveRemoteToken(mContext)).isEqualTo(mToken);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_noRemoteMedia_returnFalse() {
|
||||
public void getActiveRemoteToken_noRemoteMedia_returnNull() {
|
||||
when(mMediaController.getPlaybackInfo()).thenReturn(
|
||||
new MediaController.PlaybackInfo(MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL,
|
||||
0, 0, 0, null));
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
assertThat(mController.getActiveRemoteToken(mContext)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAvailable_returnAvailableUnsearchable() {
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(
|
||||
BasePreferenceController.AVAILABLE_UNSEARCHABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -122,17 +132,31 @@ public class RemoteVolumePreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMaxSteps_controllerNull_returnZero() {
|
||||
public void getMinValue_controllerNull_returnZero() {
|
||||
mController.mMediaController = null;
|
||||
|
||||
assertThat(mController.getMaxSteps()).isEqualTo(0);
|
||||
assertThat(mController.getMin()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMaxSteps_controllerExists_returnValue() {
|
||||
public void getMinValue_controllerExists_returnValue() {
|
||||
mController.mMediaController = mMediaController;
|
||||
|
||||
assertThat(mController.getMaxSteps()).isEqualTo(MAX_POS);
|
||||
assertThat(mController.getMin()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMaxValue_controllerNull_returnZero() {
|
||||
mController.mMediaController = null;
|
||||
|
||||
assertThat(mController.getMax()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMaxValue_controllerExists_returnValue() {
|
||||
mController.mMediaController = mMediaController;
|
||||
|
||||
assertThat(mController.getMax()).isEqualTo(MAX_POS);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -106,8 +106,10 @@ public class VolumeSeekBarPreferenceControllerTest {
|
||||
public void sliderMethods_handleNullPreference() {
|
||||
when(mHelper.getStreamVolume(mController.getAudioStream())).thenReturn(4);
|
||||
when(mHelper.getMaxVolume(mController.getAudioStream())).thenReturn(10);
|
||||
when(mHelper.getMinVolume(mController.getAudioStream())).thenReturn(1);
|
||||
|
||||
assertThat(mController.getMaxSteps()).isEqualTo(10);
|
||||
assertThat(mController.getMax()).isEqualTo(10);
|
||||
assertThat(mController.getMin()).isEqualTo(1);
|
||||
assertThat(mController.getSliderPosition()).isEqualTo(4);
|
||||
|
||||
mController.setSliderPosition(9);
|
||||
@@ -123,11 +125,19 @@ public class VolumeSeekBarPreferenceControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMaxSteps_passesAlongValue() {
|
||||
public void getMaxValue_passesAlongValue() {
|
||||
when(mPreference.getMax()).thenReturn(6);
|
||||
mController.displayPreference(mScreen);
|
||||
|
||||
assertThat(mController.getMaxSteps()).isEqualTo(6);
|
||||
assertThat(mController.getMax()).isEqualTo(6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMinValue_passesAlongValue() {
|
||||
when(mPreference.getMin()).thenReturn(1);
|
||||
mController.displayPreference(mScreen);
|
||||
|
||||
assertThat(mController.getMin()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.notification;
|
||||
|
||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class ZenModeSoundSettingsPreferenceControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
private ZenModeSoundSettingsPreferenceController mController;
|
||||
private static final String KEY_ZEN_MODE = "zen_mode";
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mController = new ZenModeSoundSettingsPreferenceController(mContext, KEY_ZEN_MODE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityStatus_available() {
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -81,12 +82,16 @@ public class PanelFragmentTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreateView_adapterGetsDataset() {
|
||||
public void onCreateView_countdownLatch_setup() {
|
||||
mPanelFragment.onCreateView(LayoutInflater.from(mContext),
|
||||
new LinearLayout(mContext), null);
|
||||
PanelSlicesAdapter adapter = mPanelFragment.mAdapter;
|
||||
PanelSlicesLoaderCountdownLatch countdownLatch =
|
||||
mPanelFragment.mPanelSlicesLoaderCountdownLatch;
|
||||
for (Uri sliecUri: mFakePanelContent.getSlices()) {
|
||||
countdownLatch.markSliceLoaded(sliecUri);
|
||||
}
|
||||
|
||||
assertThat(adapter.getData()).containsAllIn(mFakePanelContent.getSlices());
|
||||
assertThat(countdownLatch.isPanelReadyToLoad()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -23,41 +23,53 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.slice.Slice;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.slices.CustomSliceRegistry;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.android.controller.ActivityController;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class PanelSlicesAdapterTest {
|
||||
|
||||
private static final Uri DATA_URI = CustomSliceRegistry.DATA_USAGE_SLICE_URI;
|
||||
|
||||
private Context mContext;
|
||||
private PanelFragment mPanelFragment;
|
||||
private FakePanelContent mFakePanelContent;
|
||||
private FakeFeatureFactory mFakeFeatureFactory;
|
||||
private PanelFeatureProvider mPanelFeatureProvider;
|
||||
private FakeFeatureFactory mFakeFeatureFactory;
|
||||
private FakePanelContent mFakePanelContent;
|
||||
private List<LiveData<Slice>> mData = new ArrayList<>();
|
||||
|
||||
@Mock
|
||||
private LiveData<Slice> mLiveData;
|
||||
|
||||
private Slice mSlice;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
|
||||
mPanelFeatureProvider = spy(new PanelFeatureProviderImpl());
|
||||
@@ -76,12 +88,22 @@ public class PanelSlicesAdapterTest {
|
||||
.get()
|
||||
.getSupportFragmentManager()
|
||||
.findFragmentById(R.id.main_content));
|
||||
|
||||
}
|
||||
|
||||
private void constructTestLiveData(Uri uri) {
|
||||
// Create a slice to return for the LiveData
|
||||
mSlice = spy(new Slice());
|
||||
doReturn(uri).when(mSlice).getUri();
|
||||
when(mLiveData.getValue()).thenReturn(mSlice);
|
||||
mData.add(mLiveData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreateViewHolder_returnsSliceRowViewHolder() {
|
||||
constructTestLiveData(DATA_URI);
|
||||
final PanelSlicesAdapter adapter =
|
||||
new PanelSlicesAdapter(mPanelFragment, mFakePanelContent);
|
||||
new PanelSlicesAdapter(mPanelFragment, mData, 0 /* metrics category */);
|
||||
final ViewGroup view = new FrameLayout(mContext);
|
||||
final PanelSlicesAdapter.SliceRowViewHolder viewHolder =
|
||||
adapter.onCreateViewHolder(view, 0);
|
||||
@@ -89,24 +111,11 @@ public class PanelSlicesAdapterTest {
|
||||
assertThat(viewHolder.sliceView).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onBindViewHolder_bindsSlice() {
|
||||
final PanelSlicesAdapter adapter =
|
||||
new PanelSlicesAdapter(mPanelFragment, mFakePanelContent);
|
||||
final int position = 0;
|
||||
final ViewGroup view = new FrameLayout(mContext);
|
||||
final PanelSlicesAdapter.SliceRowViewHolder viewHolder =
|
||||
adapter.onCreateViewHolder(view, 0 /* view type*/);
|
||||
|
||||
adapter.onBindViewHolder(viewHolder, position);
|
||||
|
||||
assertThat(viewHolder.sliceLiveData).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonMediaOutputIndicatorSlice_shouldAllowDividerAboveAndBelow() {
|
||||
constructTestLiveData(DATA_URI);
|
||||
final PanelSlicesAdapter adapter =
|
||||
new PanelSlicesAdapter(mPanelFragment, mFakePanelContent);
|
||||
new PanelSlicesAdapter(mPanelFragment, mData, 0 /* metrics category */);
|
||||
final int position = 0;
|
||||
final ViewGroup view = new FrameLayout(mContext);
|
||||
final PanelSlicesAdapter.SliceRowViewHolder viewHolder =
|
||||
@@ -120,32 +129,10 @@ public class PanelSlicesAdapterTest {
|
||||
|
||||
@Test
|
||||
public void mediaOutputIndicatorSlice_shouldNotAllowDividerAbove() {
|
||||
PanelContent mediaOutputIndicatorSlicePanelContent = new PanelContent() {
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
return "title";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Uri> getSlices() {
|
||||
return Arrays.asList(
|
||||
MEDIA_OUTPUT_INDICATOR_SLICE_URI
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getSeeMoreIntent() {
|
||||
return new Intent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.TESTING;
|
||||
}
|
||||
};
|
||||
constructTestLiveData(MEDIA_OUTPUT_INDICATOR_SLICE_URI);
|
||||
|
||||
final PanelSlicesAdapter adapter =
|
||||
new PanelSlicesAdapter(mPanelFragment, mediaOutputIndicatorSlicePanelContent);
|
||||
new PanelSlicesAdapter(mPanelFragment, mData, 0 /* metrics category */);
|
||||
final int position = 0;
|
||||
final ViewGroup view = new FrameLayout(mContext);
|
||||
final PanelSlicesAdapter.SliceRowViewHolder viewHolder =
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.panel;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class PanelSlicesLoaderCountdownLatchTest {
|
||||
|
||||
private Context mContext;
|
||||
private PanelSlicesLoaderCountdownLatch mSliceCountdownLatch;
|
||||
|
||||
private static final Uri[] URIS = new Uri[] {
|
||||
Uri.parse("content://testUri"),
|
||||
Uri.parse("content://wowUri"),
|
||||
Uri.parse("content://boxTurtle")
|
||||
};
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mSliceCountdownLatch = new PanelSlicesLoaderCountdownLatch(URIS.length);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void hasLoaded_newObject_returnsFalse() {
|
||||
assertThat(mSliceCountdownLatch.isSliceLoaded(URIS[0])).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasLoaded_markSliceLoaded_returnsTrue() {
|
||||
mSliceCountdownLatch.markSliceLoaded(URIS[0]);
|
||||
|
||||
assertThat(mSliceCountdownLatch.isSliceLoaded(URIS[0])).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void markSliceLoaded_onlyCountsDownUniqueUris() {
|
||||
for (int i = 0; i < URIS.length; i++) {
|
||||
mSliceCountdownLatch.markSliceLoaded(URIS[0]);
|
||||
}
|
||||
|
||||
assertThat(mSliceCountdownLatch.isPanelReadyToLoad()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void areSlicesReadyToLoad_allSlicesLoaded_returnsTrue() {
|
||||
for (int i = 0; i < URIS.length; i++) {
|
||||
mSliceCountdownLatch.markSliceLoaded(URIS[i]);
|
||||
}
|
||||
|
||||
assertThat(mSliceCountdownLatch.isPanelReadyToLoad()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void areSlicesReadyToLoad_onlyReturnsTrueOnce() {
|
||||
for (int i = 0; i < URIS.length; i++) {
|
||||
mSliceCountdownLatch.markSliceLoaded(URIS[i]);
|
||||
}
|
||||
|
||||
// Verify that it returns true once
|
||||
assertThat(mSliceCountdownLatch.isPanelReadyToLoad()).isTrue();
|
||||
// Verify the second call returns false without external state change
|
||||
assertThat(mSliceCountdownLatch.isPanelReadyToLoad()).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.sim;
|
||||
|
||||
import static com.android.settings.sim.SimDialogActivity.PREFERRED_PICK;
|
||||
import static com.android.settings.sim.SimDialogActivity.PREFERRED_SIM;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = ShadowAlertDialogCompat.class)
|
||||
public class PreferredSimDialogFragmentTest extends
|
||||
SimDialogFragmentTestBase<PreferredSimDialogFragment> {
|
||||
|
||||
@Override
|
||||
public void setUp() {
|
||||
super.setUp();
|
||||
setDialogType(PREFERRED_PICK);
|
||||
mFragment = spy(PreferredSimDialogFragment.newInstance());
|
||||
doReturn(mSubscriptionManager).when(mFragment).getSubscriptionManager();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreateDialog_noSims_dismissed() {
|
||||
when(mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(anyInt()))
|
||||
.thenReturn(null);
|
||||
mIntent.putExtra(PREFERRED_SIM, 0);
|
||||
startDialog();
|
||||
verify(mFragment).dismiss();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreateDialog_oneSimWrongSlotArgument_dismissed() {
|
||||
when(mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(1)).thenReturn(null);
|
||||
mIntent.putExtra(PREFERRED_SIM, 1);
|
||||
startDialog();
|
||||
verify(mFragment).dismiss();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreateDialog_twoSimsSelectFirst_correctMessage() {
|
||||
mIntent.putExtra(PREFERRED_SIM, 0);
|
||||
|
||||
final AlertDialog alertDialog = startDialog();
|
||||
final ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(alertDialog);
|
||||
final String message = (String) shadowDialog.getMessage();
|
||||
assertThat(message).contains(SIM1_NAME);
|
||||
assertThat(message).doesNotContain(SIM2_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreateDialog_twoSimsSelectSecond_correctMessage() {
|
||||
mIntent.putExtra(PREFERRED_SIM, 1);
|
||||
|
||||
final AlertDialog alertDialog = startDialog();
|
||||
final ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(alertDialog);
|
||||
final String message = (String) shadowDialog.getMessage();
|
||||
assertThat(message).contains(SIM2_NAME);
|
||||
assertThat(message).doesNotContain(SIM1_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onClick_yesClicked_callsOnSubscriptionSelected() {
|
||||
mIntent.putExtra(PREFERRED_SIM, 0);
|
||||
|
||||
final AlertDialog alertDialog = startDialog();
|
||||
|
||||
final SimDialogActivity activity = (SimDialogActivity) spy(mFragment.getActivity());
|
||||
doReturn(activity).when(mFragment).getActivity();
|
||||
doNothing().when(activity).onSubscriptionSelected(anyInt(), anyInt());
|
||||
|
||||
mFragment.onClick(alertDialog, DialogInterface.BUTTON_POSITIVE);
|
||||
verify(activity).onSubscriptionSelected(PREFERRED_PICK, SIM1_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onClick_noClicked_doesNotCallOnSubscriptionSelected() {
|
||||
mIntent.putExtra(PREFERRED_SIM, 0);
|
||||
|
||||
final AlertDialog alertDialog = startDialog();
|
||||
|
||||
final SimDialogActivity activity = (SimDialogActivity) spy(mFragment.getActivity());
|
||||
doReturn(activity).when(mFragment).getActivity();
|
||||
doNothing().when(activity).onSubscriptionSelected(anyInt(), anyInt());
|
||||
|
||||
mFragment.onClick(alertDialog, DialogInterface.BUTTON_NEGATIVE);
|
||||
verify(activity, never()).onSubscriptionSelected(anyInt(), anyInt());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.sim;
|
||||
|
||||
import static com.android.settings.sim.SimDialogActivity.DIALOG_TYPE_KEY;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.shadows.androidx.fragment.FragmentController;
|
||||
|
||||
public abstract class SimDialogFragmentTestBase<T extends SimDialogFragment> {
|
||||
protected static final int SIM1_ID = 111;
|
||||
protected static final int SIM2_ID = 222;
|
||||
protected static final String SIM1_NAME = "sim111";
|
||||
protected static final String SIM2_NAME = "sim222";
|
||||
|
||||
@Mock
|
||||
protected SubscriptionManager mSubscriptionManager;
|
||||
@Mock
|
||||
protected SubscriptionInfo mSim1;
|
||||
@Mock
|
||||
protected SubscriptionInfo mSim2;
|
||||
|
||||
protected T mFragment;
|
||||
protected Intent mIntent;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mIntent = new Intent();
|
||||
|
||||
when(mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(0)).thenReturn(mSim1);
|
||||
when(mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(1)).thenReturn(mSim2);
|
||||
|
||||
when(mSim1.getSubscriptionId()).thenReturn(SIM1_ID);
|
||||
when(mSim1.getDisplayName()).thenReturn(SIM1_NAME);
|
||||
when(mSim2.getSubscriptionId()).thenReturn(SIM2_ID);
|
||||
when(mSim2.getDisplayName()).thenReturn(SIM2_NAME);
|
||||
}
|
||||
|
||||
protected void setDialogType(int dialogType) {
|
||||
mIntent.putExtra(DIALOG_TYPE_KEY, dialogType);
|
||||
}
|
||||
|
||||
protected AlertDialog startDialog() {
|
||||
final FragmentController controller = FragmentController.of(mFragment,
|
||||
SimDialogActivity.class, mIntent);
|
||||
controller.create(0 /* containerViewId */, null /* bundle */).start().visible();
|
||||
return ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.sim;
|
||||
|
||||
import static com.android.settings.sim.SimDialogActivity.DATA_PICK;
|
||||
import static com.android.settings.sim.SimDialogActivity.SMS_PICK;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.telephony.SubscriptionManager;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = ShadowAlertDialogCompat.class)
|
||||
public class SimListDialogFragmentTest extends SimDialogFragmentTestBase<SimListDialogFragment> {
|
||||
|
||||
@Test
|
||||
public void onCreateDialog_noSubscriptions_dismissed() {
|
||||
final int dialogType = DATA_PICK;
|
||||
setDialogType(dialogType);
|
||||
mFragment = spy(SimListDialogFragment.newInstance(dialogType, R.string.select_sim_for_data,
|
||||
false /* includeAskEveryTime */));
|
||||
doReturn(null).when(mFragment).getCurrentSubscriptions();
|
||||
startDialog();
|
||||
verify(mFragment).dismiss();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreateDialog_twoSubscriptionsNoAskEveryTime_twoSubsForDisplay() {
|
||||
final int dialogType = DATA_PICK;
|
||||
setDialogType(dialogType);
|
||||
mFragment = spy(SimListDialogFragment.newInstance(dialogType, R.string.select_sim_for_data,
|
||||
false /* includeAskEveryTime */));
|
||||
doReturn(Arrays.asList(mSim1, mSim2)).when(mFragment).getCurrentSubscriptions();
|
||||
// Avoid problems robolectric has with our real adapter.
|
||||
doNothing().when(mFragment).setAdapter(any());
|
||||
final AlertDialog alertDialog = startDialog();
|
||||
assertThat(mFragment.mSubscriptions).hasSize(2);
|
||||
|
||||
final SimDialogActivity activity = (SimDialogActivity) spy(mFragment.getActivity());
|
||||
doReturn(activity).when(mFragment).getActivity();
|
||||
doNothing().when(activity).onSubscriptionSelected(anyInt(), anyInt());
|
||||
|
||||
mFragment.onClick(alertDialog, 1);
|
||||
verify(activity).onSubscriptionSelected(dialogType, SIM2_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onCreateDialog_twoSubscriptionsAskEveryTime_threeSubsForDisplay() {
|
||||
final int dialogType = SMS_PICK;
|
||||
setDialogType(dialogType);
|
||||
mFragment = spy(SimListDialogFragment.newInstance(dialogType, R.string.select_sim_for_sms,
|
||||
true /* includeAskEveryTime */));
|
||||
doReturn(Arrays.asList(mSim1, mSim2)).when(mFragment).getCurrentSubscriptions();
|
||||
// Avoid problems robolectric has with our real adapter.
|
||||
doNothing().when(mFragment).setAdapter(any());
|
||||
final AlertDialog alertDialog = startDialog();
|
||||
assertThat(mFragment.mSubscriptions).hasSize(3);
|
||||
assertThat(mFragment.mSubscriptions.get(0)).isNull();
|
||||
|
||||
final SimDialogActivity activity = (SimDialogActivity) spy(mFragment.getActivity());
|
||||
doReturn(activity).when(mFragment).getActivity();
|
||||
doNothing().when(activity).onSubscriptionSelected(anyInt(), anyInt());
|
||||
|
||||
mFragment.onClick(alertDialog, 0);
|
||||
verify(activity).onSubscriptionSelected(dialogType,
|
||||
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
|
||||
}
|
||||
}
|
||||
@@ -191,8 +191,8 @@ public class SliceBroadcastReceiverTest {
|
||||
.build();
|
||||
final ContentResolver resolver = mock(ContentResolver.class);
|
||||
doReturn(resolver).when(mContext).getContentResolver();
|
||||
final int position = FakeSliderController.MAX_STEPS - 1;
|
||||
final int oldPosition = FakeSliderController.MAX_STEPS;
|
||||
final int position = FakeSliderController.MAX_VALUE - 1;
|
||||
final int oldPosition = FakeSliderController.MAX_VALUE;
|
||||
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
|
||||
insertSpecialCase(FakeSliderController.class, key);
|
||||
|
||||
@@ -310,8 +310,8 @@ public class SliceBroadcastReceiverTest {
|
||||
|
||||
// Insert Fake Slider into Database
|
||||
final String key = "key";
|
||||
final int position = FakeSliderController.MAX_STEPS - 1;
|
||||
final int oldPosition = FakeSliderController.MAX_STEPS;
|
||||
final int position = FakeSliderController.MAX_VALUE - 1;
|
||||
final int oldPosition = FakeSliderController.MAX_VALUE;
|
||||
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
|
||||
insertSpecialCase(FakeSliderController.class, key);
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ public class FakeSliderController extends SliderPreferenceController {
|
||||
|
||||
public static final String AVAILABILITY_KEY = "fake_slider_availability_key";
|
||||
|
||||
public static final int MAX_STEPS = 9;
|
||||
public static final int MAX_VALUE = 9;
|
||||
|
||||
private static final String SETTING_KEY = "fake_slider_key";
|
||||
|
||||
@@ -44,8 +44,13 @@ public class FakeSliderController extends SliderPreferenceController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSteps() {
|
||||
return MAX_STEPS;
|
||||
public int getMax() {
|
||||
return MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMin() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,12 +18,16 @@ 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.os.Parcelable;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
@@ -39,9 +43,10 @@ public class SeekBarPreferenceTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
|
||||
mSeekBarPreference = new SeekBarPreference(mContext);
|
||||
mSeekBarPreference = spy(new SeekBarPreference(mContext));
|
||||
mSeekBarPreference.setMax(MAX);
|
||||
mSeekBarPreference.setMin(MIN);
|
||||
mSeekBarPreference.setProgress(PROGRESS);
|
||||
@@ -59,4 +64,18 @@ public class SeekBarPreferenceTest {
|
||||
assertThat(preference.getMin()).isEqualTo(MIN);
|
||||
assertThat(preference.getProgress()).isEqualTo(PROGRESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSelectable_disabledByAdmin_returnTrue() {
|
||||
when(mSeekBarPreference.isDisabledByAdmin()).thenReturn(true);
|
||||
|
||||
assertThat(mSeekBarPreference.isSelectable()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSelectable_notDisabledByAdmin_returnFalse() {
|
||||
when(mSeekBarPreference.isDisabledByAdmin()).thenReturn(false);
|
||||
|
||||
assertThat(mSeekBarPreference.isSelectable()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,13 @@ import static org.mockito.Mockito.doReturn;
|
||||
import android.content.Intent;
|
||||
import android.net.wifi.WifiConfiguration;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
|
||||
import com.android.settings.testutils.shadow.ShadowConnectivityManager;
|
||||
import com.android.settings.testutils.shadow.ShadowWifiManager;
|
||||
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -72,7 +75,7 @@ public class WifiDialogActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSubmit_shouldNotConnectToNetwork_whenConnectForCallerIsFalse() {
|
||||
public void onSubmit_whenConnectForCallerIsFalse_shouldNotConnectToNetwork() {
|
||||
WifiDialogActivity activity =
|
||||
Robolectric.buildActivity(
|
||||
WifiDialogActivity.class,
|
||||
@@ -88,4 +91,24 @@ public class WifiDialogActivityTest {
|
||||
|
||||
assertThat(ShadowWifiManager.get().savedWifiConfig).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onSubmit_whenLaunchInSetupFlow_shouldBeLightThemeForWifiDialog() {
|
||||
WifiDialogActivity activity =
|
||||
Robolectric.buildActivity(
|
||||
WifiDialogActivity.class,
|
||||
new Intent()
|
||||
.putExtra(WifiDialogActivity.KEY_CONNECT_FOR_CALLER, false)
|
||||
.putExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, true)
|
||||
.putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, true))
|
||||
.setup().get();
|
||||
WifiDialog dialog = (WifiDialog) ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||
|
||||
assertThat(dialog).isNotNull();
|
||||
|
||||
activity.onSubmit(dialog);
|
||||
|
||||
assertThat(dialog.getContext().getThemeResId())
|
||||
.isEqualTo(R.style.SuwAlertDialogThemeCompat_Light);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
|
||||
import com.android.settings.wifi.WifiDialog.WifiDialogListener;
|
||||
import com.android.settingslib.wifi.AccessPoint;
|
||||
@@ -41,4 +42,16 @@ public class WifiDialogTest {
|
||||
assertThat(modal.getContext().getThemeResId())
|
||||
.isEqualTo(wifiDialog.getContext().getThemeResId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createModal_whenSetTheme_shouldBeCustomizedTheme() {
|
||||
WifiDialog modal = WifiDialog.createModal(mContext, mListener, mockAccessPoint,
|
||||
WifiConfigUiBase.MODE_CONNECT, R.style.SuwAlertDialogThemeCompat_Light);
|
||||
|
||||
WifiDialog wifiDialog = new WifiDialog(mContext, mListener, mockAccessPoint,
|
||||
WifiConfigUiBase.MODE_CONNECT, R.style.SuwAlertDialogThemeCompat_Light,
|
||||
false /* hideSubmitButton */);
|
||||
assertThat(modal.getContext().getThemeResId())
|
||||
.isEqualTo(wifiDialog.getContext().getThemeResId());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user