Snap for 8310722 from 9793acfafd to tm-release

Change-Id: I8c950e2f8f59802eb17f2a1f2a2d1786d4a797d1
This commit is contained in:
Android Build Coastguard Worker
2022-03-17 01:09:03 +00:00
39 changed files with 925 additions and 532 deletions

View File

@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_marginBottom="12dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_marginTop="12dp"
android:textSize="18sp"
android:text="@string/confirm_convert_to_fbe_warning" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:orientation="horizontal">
<Button
android:id="@+id/button_confirm_convert_fbe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginBottom="12dp"
android:text="@string/button_confirm_convert_fbe" />
</LinearLayout>
</LinearLayout>

View File

@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_marginBottom="12dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/preference_no_icon_padding_start"
android:layout_marginEnd="12dp"
android:layout_marginTop="12dp"
android:textSize="18sp"
android:text="@string/convert_to_fbe_warning" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:orientation="horizontal">
<Button
android:id="@+id/button_convert_fbe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginBottom="12dp"
android:text="@string/button_convert_fbe" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/entity_header"
style="@style/EntityHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:orientation="vertical">
<TextView
android:id="@+id/entity_header_title"
style="@style/TextAppearance.EntityHeaderTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:singleLine="false"
android:ellipsize="marquee"
android:textDirection="locale"/>
<TextView
android:id="@+id/entity_header_summary"
style="@style/TextAppearance.EntityHeaderSummary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="4dp"
android:singleLine="false"
android:ellipsize="marquee"
android:textDirection="locale"/>
<ImageView
android:id="@+id/entity_header_icon"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_marginTop="24dp"
android:scaleType="fitCenter"
android:antialias="true"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/le_bluetooth_battery_start_margin"
android:orientation="vertical">
<TextView
android:id="@+id/bt_battery_case_title"
style="@style/TextAppearance.EntityHeaderTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
android:gravity="start|center_vertical"
android:ellipsize="end"
android:textDirection="locale"
android:text="@string/bluetooth_middle_name"
android:textSize="@dimen/advanced_bluetooth_header_title_text_size"
android:visibility="gone"/>
<TextView
android:id="@+id/bt_battery_left_title"
style="@style/TextAppearance.EntityHeaderTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
android:gravity="start|center_vertical"
android:ellipsize="end"
android:textDirection="locale"
android:text="@string/bluetooth_left_name"
android:textSize="@dimen/advanced_bluetooth_header_title_text_size"/>
<TextView
android:id="@+id/bt_battery_right_title"
style="@style/TextAppearance.EntityHeaderTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
android:gravity="start|center_vertical"
android:ellipsize="end"
android:textDirection="locale"
android:text="@string/bluetooth_right_name"
android:textSize="@dimen/advanced_bluetooth_header_title_text_size"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/le_bluetooth_summary_start_margin"
android:orientation="vertical">
<TextView
android:id="@+id/bt_battery_case_summary"
style="@style/TextAppearance.EntityHeaderSummary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
android:padding="@dimen/le_bluetooth_summary_padding"
android:drawablePadding="@dimen/le_bluetooth_summary_drawable_padding"
android:visibility="gone"/>
<TextView
android:id="@+id/bt_battery_left_summary"
style="@style/TextAppearance.EntityHeaderSummary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
android:padding="@dimen/le_bluetooth_summary_padding"
android:drawablePadding="@dimen/le_bluetooth_summary_drawable_padding"/>
<TextView
android:id="@+id/bt_battery_right_summary"
style="@style/TextAppearance.EntityHeaderSummary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
android:padding="@dimen/le_bluetooth_summary_padding"
android:drawablePadding="@dimen/le_bluetooth_summary_drawable_padding"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -399,6 +399,13 @@
<dimen name="advanced_bluetooth_battery_height">27.5dp</dimen> <dimen name="advanced_bluetooth_battery_height">27.5dp</dimen>
<dimen name="advanced_bluetooth_battery_right_margin">-4dp</dimen> <dimen name="advanced_bluetooth_battery_right_margin">-4dp</dimen>
<!-- Header layout of LE audio bluetooth device at bluretooth device detalis -->
<dimen name="le_bluetooth_battery_top_margin">5dp</dimen>
<dimen name="le_bluetooth_battery_start_margin">10dp</dimen>
<dimen name="le_bluetooth_summary_drawable_padding">6dp</dimen>
<dimen name="le_bluetooth_summary_start_margin">20dp</dimen>
<dimen name="le_bluetooth_summary_padding">1.5dp</dimen>
<!-- Developer option bluetooth settings dialog --> <!-- Developer option bluetooth settings dialog -->
<dimen name="developer_option_dialog_margin_start">8dp</dimen> <dimen name="developer_option_dialog_margin_start">8dp</dimen>
<dimen name="developer_option_dialog_margin_top">8dp</dimen> <dimen name="developer_option_dialog_margin_top">8dp</dimen>

View File

@@ -5405,7 +5405,7 @@
<!-- Description for the accessibility button in gesture navigation. Explain how this page works. [CHAR LIMIT=NONE] --> <!-- Description for the accessibility button in gesture navigation. Explain how this page works. [CHAR LIMIT=NONE] -->
<string name="accessibility_button_gesture_description"><b>To get started</b>\n1. Go to accessibility settings\n2. Select a feature and tap the shortcut\n3. Choose whether you want to use a button or gesture to access the feature</string> <string name="accessibility_button_gesture_description"><b>To get started</b>\n1. Go to accessibility settings\n2. Select a feature and tap the shortcut\n3. Choose whether you want to use a button or gesture to access the feature</string>
<!-- Description for the accessibility button page. Explain how this page works. [CHAR LIMIT=NONE] --> <!-- Description for the accessibility button page. Explain how this page works. [CHAR LIMIT=NONE] -->
<string name="accessibility_button_description"><b>To get started</b>\n1. Go to accessibility settings\n2. Select a feature and tap the shortcut\n3. Choose the button to use to access the feature</string> <string name="accessibility_button_description"><b>To get started</b>\n1. Go to accessibility settings\n2. Select a feature and tap the shortcut\n3. Choose the button to access the feature</string>
<!-- Title for the button or gesture of the accessibility button. [CHAR LIMIT=35] --> <!-- Title for the button or gesture of the accessibility button. [CHAR LIMIT=35] -->
<string name="accessibility_button_or_gesture_title">Use button or gesture</string> <string name="accessibility_button_or_gesture_title">Use button or gesture</string>
<!-- Title for the location of the accessibility button. [CHAR LIMIT=35] --> <!-- Title for the location of the accessibility button. [CHAR LIMIT=35] -->
@@ -8296,7 +8296,7 @@
<string name="keywords_sounds_and_notifications_interruptions">dont don\u2019t disturb, interrupt, interruption, break</string> <string name="keywords_sounds_and_notifications_interruptions">dont don\u2019t disturb, interrupt, interruption, break</string>
<string name="keywords_app">RAM</string> <string name="keywords_app">RAM</string>
<string name="keywords_location">nearby, location, history, reporting, GPS</string> <string name="keywords_location">nearby, location, history, reporting, GPS</string>
<string name="keywords_accounts">account, add an account, work profile, add account</string> <string name="keywords_accounts">account, add an account, work profile, add account, remove, delete</string>
<string name="keywords_users">restriction, restrict, restricted</string> <string name="keywords_users">restriction, restrict, restricted</string>
<string name="keywords_keyboard_and_ime">text correction, correct, sound, vibrate, auto, language, gesture, suggest, suggestion, theme, offensive, word, type, emoji, international</string> <string name="keywords_keyboard_and_ime">text correction, correct, sound, vibrate, auto, language, gesture, suggest, suggestion, theme, offensive, word, type, emoji, international</string>
<string name="keywords_reset_apps">reset, preferences, default</string> <string name="keywords_reset_apps">reset, preferences, default</string>
@@ -9852,7 +9852,7 @@
<string name="zen_mode_people_calls_messages_section_title">Who can interrupt</string> <string name="zen_mode_people_calls_messages_section_title">Who can interrupt</string>
<!-- [CHAR LIMIT=NONE] Zen mode settings: people screen footer --> <!-- [CHAR LIMIT=NONE] Zen mode settings: people screen footer -->
<string name="zen_mode_people_footer" translatable="false">Even if messaging or calling apps can\u0027t notify you, people you choose here can still reach you through those apps</string> <string name="zen_mode_people_footer">Even if messaging or calling apps can\u0027t notify you, people you choose here can still reach you through those apps</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Allow calls toggle title --> <!-- [CHAR LIMIT=40] Zen mode settings: Allow calls toggle title -->
<string name="zen_mode_calls_title">Calls</string> <string name="zen_mode_calls_title">Calls</string>
@@ -11596,11 +11596,6 @@
<!-- Title for the See more preference item in Special app access settings [CHAR LIMIT=30] --> <!-- Title for the See more preference item in Special app access settings [CHAR LIMIT=30] -->
<string name="special_access_more">See more</string> <string name="special_access_more">See more</string>
<!-- Developer option to convert to file encryption - final warning -->
<string name="confirm_convert_to_fbe_warning">Really wipe user data and convert to file encryption?</string>
<!-- Developer option to convert to file encryption - final button -->
<string name="button_confirm_convert_fbe">Wipe and convert</string>
<!-- Reset rate-limiting in the system service ShortcutManager. "ShortcutManager" is the name of a system service and not translatable. <!-- Reset rate-limiting in the system service ShortcutManager. "ShortcutManager" is the name of a system service and not translatable.
If the word "rate-limit" is hard to translate, use "Reset ShortcutManager API call limit" as the source text, which means If the word "rate-limit" is hard to translate, use "Reset ShortcutManager API call limit" as the source text, which means
the same thing in this context. the same thing in this context.

View File

@@ -34,6 +34,14 @@
settings:searchable="false" settings:searchable="false"
settings:controller="com.android.settings.bluetooth.AdvancedBluetoothDetailsHeaderController"/> settings:controller="com.android.settings.bluetooth.AdvancedBluetoothDetailsHeaderController"/>
<com.android.settingslib.widget.LayoutPreference
android:key="le_audio_bluetooth_device_header"
android:layout="@layout/le_audio_bt_entity_header"
android:selectable="false"
settings:allowDividerBelow="true"
settings:searchable="false"
settings:controller="com.android.settings.bluetooth.LeAudioBluetoothDetailsHeaderController"/>
<com.android.settingslib.widget.ActionButtonsPreference <com.android.settingslib.widget.ActionButtonsPreference
android:key="action_buttons" android:key="action_buttons"
settings:allowDividerBelow="true"/> settings:allowDividerBelow="true"/>

View File

@@ -92,12 +92,6 @@
android:summary="@string/runningservices_settings_summary" android:summary="@string/runningservices_settings_summary"
android:fragment="com.android.settings.applications.RunningServices" /> android:fragment="com.android.settings.applications.RunningServices" />
<Preference
android:key="convert_to_file_encryption"
android:title="@string/convert_to_file_encryption"
android:summary="@string/convert_to_file_encryption_enabled"
android:fragment="com.android.settings.applications.ConvertToFbe" />
<com.android.settings.development.ColorModePreference <com.android.settings.development.ColorModePreference
android:key="picture_color_mode" android:key="picture_color_mode"
android:title="@string/picture_color_mode" android:title="@string/picture_color_mode"

View File

@@ -25,9 +25,7 @@ import androidx.preference.PreferenceViewHolder;
import com.android.settingslib.widget.FooterPreference; import com.android.settingslib.widget.FooterPreference;
/** /** A custom preference acting as footer of a page. Disables the movement method by default. */
* A custom preference acting as footer of a page. Disables the movement method by default.
*/
public final class AccessibilityFooterPreference extends FooterPreference { public final class AccessibilityFooterPreference extends FooterPreference {
private boolean mLinkEnabled; private boolean mLinkEnabled;
@@ -46,12 +44,16 @@ public final class AccessibilityFooterPreference extends FooterPreference {
final TextView title = holder.itemView.findViewById(android.R.id.title); final TextView title = holder.itemView.findViewById(android.R.id.title);
if (mLinkEnabled) { if (mLinkEnabled) {
// When a TextView has a movement method, it will set the view to clickable. This makes // When a TextView has a movement method, it will set the view to focusable and
// View.onTouchEvent always return true and consumes the touch event, essentially // clickable. This makes View.onTouchEvent always return true and consumes the touch
// nullifying any return values of MovementMethod.onTouchEvent. // event, essentially nullifying any return values of MovementMethod.onTouchEvent.
// To still allow propagating touch events to the parent when this view doesn't have // To still allow propagating touch events to the parent when this view doesn't have
// links, we only set the movement method here if the text contains links. // links, we only set the movement method here if the text contains links.
title.setMovementMethod(LinkMovementMethod.getInstance()); title.setMovementMethod(LinkMovementMethod.getInstance());
// Groups of related title and link content by making the container focusable,
// then make all the children inside not focusable.
title.setFocusable(false);
} else { } else {
title.setMovementMethod(/* movement= */ null); title.setMovementMethod(/* movement= */ null);
} }

View File

@@ -122,5 +122,8 @@ public class AccessibilityFooterPreferenceController extends BasePreferenceContr
} else { } else {
footerPreference.setLinkEnabled(false); footerPreference.setLinkEnabled(false);
} }
// Grouping subcomponents to make more accessible.
footerPreference.setSelectable(false);
} }
} }

View File

@@ -19,6 +19,9 @@ package com.android.settings.accessibility;
import android.content.Context; import android.content.Context;
import android.provider.Settings; import android.provider.Settings;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController; import com.android.settings.core.TogglePreferenceController;
@@ -27,6 +30,7 @@ import com.android.settings.core.TogglePreferenceController;
*/ */
public class HighTextContrastPreferenceController extends TogglePreferenceController implements public class HighTextContrastPreferenceController extends TogglePreferenceController implements
TextReadingResetController.ResetStateListener { TextReadingResetController.ResetStateListener {
private SwitchPreference mSwitchPreference;
public HighTextContrastPreferenceController(Context context, String preferenceKey) { public HighTextContrastPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey); super(context, preferenceKey);
@@ -54,8 +58,15 @@ public class HighTextContrastPreferenceController extends TogglePreferenceContro
return R.string.menu_key_accessibility; return R.string.menu_key_accessibility;
} }
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mSwitchPreference = screen.findPreference(getPreferenceKey());
}
@Override @Override
public void resetState() { public void resetState() {
setChecked(false); setChecked(false);
updateState(mSwitchPreference);
} }
} }

View File

@@ -564,13 +564,6 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
createFooterPreference(getPreferenceScreen(), mDescription, createFooterPreference(getPreferenceScreen(), mDescription,
getString(R.string.accessibility_introduction_title, mPackageName)); getString(R.string.accessibility_introduction_title, mPackageName));
} }
if (TextUtils.isEmpty(mHtmlDescription) && TextUtils.isEmpty(mDescription)) {
final CharSequence defaultDescription =
getText(R.string.accessibility_service_default_description);
createFooterPreference(getPreferenceScreen(), defaultDescription,
getString(R.string.accessibility_introduction_title, mPackageName));
}
} }

View File

@@ -1,55 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications;
import android.app.settings.SettingsEnums;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
public class ConfirmConvertToFbe extends SettingsPreferenceFragment {
static final String TAG = "ConfirmConvertToFBE";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.confirm_convert_fbe, null);
final Button button = (Button) rootView.findViewById(R.id.button_confirm_convert_fbe);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_FACTORY_RESET);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.setPackage("android");
intent.putExtra(Intent.EXTRA_REASON, "convert_fbe");
getActivity().sendBroadcast(intent);
}
});
return rootView;
}
@Override
public int getMetricsCategory() {
return SettingsEnums.CONVERT_FBE_CONFIRM;
}
}

View File

@@ -1,97 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.android.settings.R;
import com.android.settings.core.InstrumentedFragment;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.password.ChooseLockSettingsHelper;
/* Class to prompt for conversion of userdata to file based encryption
*/
public class ConvertToFbe extends InstrumentedFragment {
static final String TAG = "ConvertToFBE";
private static final int KEYGUARD_REQUEST = 55;
private boolean runKeyguardConfirmation(int request) {
Resources res = getActivity().getResources();
final ChooseLockSettingsHelper.Builder builder =
new ChooseLockSettingsHelper.Builder(getActivity(), this);
return builder.setRequestCode(request)
.setTitle(res.getText(R.string.convert_to_file_encryption))
.show();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().setTitle(R.string.convert_to_file_encryption);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.convert_fbe, null);
final Button button = rootView.findViewById(R.id.button_convert_fbe);
button.setOnClickListener(v -> {
if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
convert();
}
});
return rootView;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode != KEYGUARD_REQUEST) {
return;
}
// If the user entered a valid keyguard credential, start the conversion
// process
if (resultCode == Activity.RESULT_OK) {
convert();
}
}
private void convert() {
new SubSettingLauncher(getContext())
.setDestination(ConfirmConvertToFbe.class.getName())
.setTitleRes(R.string.convert_to_file_encryption)
.setSourceMetricsCategory(getMetricsCategory())
.launch();
}
@Override
public int getMetricsCategory() {
return SettingsEnums.CONVERT_FBE;
}
}

View File

@@ -81,9 +81,11 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
private static final int STAGE_CENTER = 0; private static final int STAGE_CENTER = 0;
private static final int STAGE_GUIDED = 1; private static final int STAGE_GUIDED = 1;
private static final int STAGE_FINGERTIP = 2; private static final int STAGE_FINGERTIP = 2;
private static final int STAGE_EDGES = 3; private static final int STAGE_LEFT_EDGE = 3;
private static final int STAGE_RIGHT_EDGE = 4;
@IntDef({STAGE_UNKNOWN, STAGE_CENTER, STAGE_GUIDED, STAGE_FINGERTIP, STAGE_EDGES}) @IntDef({STAGE_UNKNOWN, STAGE_CENTER, STAGE_GUIDED, STAGE_FINGERTIP, STAGE_LEFT_EDGE,
STAGE_RIGHT_EDGE})
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
private @interface EnrollStage {} private @interface EnrollStage {}
@@ -132,7 +134,8 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
private boolean mIsAccessibilityEnabled; private boolean mIsAccessibilityEnabled;
private LottieAnimationView mIllustrationLottie; private LottieAnimationView mIllustrationLottie;
private boolean mHaveShownUdfpsTipLottie; private boolean mHaveShownUdfpsTipLottie;
private boolean mHaveShownUdfpsSideLottie; private boolean mHaveShownUdfpsLeftEdgeLottie;
private boolean mHaveShownUdfpsRightEdgeLottie;
private boolean mShouldShowLottie; private boolean mShouldShowLottie;
private OrientationEventListener mOrientationEventListener; private OrientationEventListener mOrientationEventListener;
@@ -372,12 +375,31 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
} }
break; break;
case STAGE_EDGES: case STAGE_LEFT_EDGE:
setHeaderText(R.string.security_settings_udfps_enroll_edge_title); setHeaderText(R.string.security_settings_udfps_enroll_edge_title);
if (!mHaveShownUdfpsSideLottie && mIllustrationLottie != null) { if (!mHaveShownUdfpsLeftEdgeLottie && mIllustrationLottie != null) {
mHaveShownUdfpsSideLottie = true; mHaveShownUdfpsLeftEdgeLottie = true;
setDescriptionText(""); setDescriptionText("");
mIllustrationLottie.setAnimation(R.raw.udfps_edge_hint_lottie); mIllustrationLottie.setAnimation(R.raw.udfps_left_edge_hint_lottie);
mIllustrationLottie.setVisibility(View.VISIBLE);
mIllustrationLottie.playAnimation();
mIllustrationLottie.setContentDescription(
getString(R.string.security_settings_udfps_side_fingerprint_help));
} else if (mIllustrationLottie == null) {
if (isStageHalfCompleted()) {
setDescriptionText(
R.string.security_settings_fingerprint_enroll_repeat_message);
} else {
setDescriptionText(R.string.security_settings_udfps_enroll_edge_message);
}
}
break;
case STAGE_RIGHT_EDGE:
setHeaderText(R.string.security_settings_udfps_enroll_edge_title);
if (!mHaveShownUdfpsRightEdgeLottie && mIllustrationLottie != null) {
mHaveShownUdfpsRightEdgeLottie = true;
setDescriptionText("");
mIllustrationLottie.setAnimation(R.raw.udfps_right_edge_hint_lottie);
mIllustrationLottie.setVisibility(View.VISIBLE); mIllustrationLottie.setVisibility(View.VISIBLE);
mIllustrationLottie.playAnimation(); mIllustrationLottie.playAnimation();
mIllustrationLottie.setContentDescription( mIllustrationLottie.setContentDescription(
@@ -422,8 +444,10 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
return STAGE_GUIDED; return STAGE_GUIDED;
} else if (progressSteps < getStageThresholdSteps(2)) { } else if (progressSteps < getStageThresholdSteps(2)) {
return STAGE_FINGERTIP; return STAGE_FINGERTIP;
} else if (progressSteps < getStageThresholdSteps(3)) {
return STAGE_LEFT_EDGE;
} else { } else {
return STAGE_EDGES; return STAGE_RIGHT_EDGE;
} }
} }

View File

@@ -16,6 +16,7 @@
package com.android.settings.bluetooth; package com.android.settings.bluetooth;
import android.bluetooth.BluetoothProfile;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.text.TextUtils; import android.text.TextUtils;
@@ -53,7 +54,10 @@ public class BluetoothDetailsHeaderController extends BluetoothDetailsController
@Override @Override
public boolean isAvailable() { public boolean isAvailable() {
return !Utils.isAdvancedDetailsHeader(mCachedDevice.getDevice()); boolean hasLeAudio = mCachedDevice.getConnectableProfiles()
.stream()
.anyMatch(profile -> profile.getProfileId() == BluetoothProfile.LE_AUDIO);
return !Utils.isAdvancedDetailsHeader(mCachedDevice.getDevice()) && !hasLeAudio;
} }
@Override @Override

View File

@@ -16,10 +16,12 @@
package com.android.settings.bluetooth; package com.android.settings.bluetooth;
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile;
import android.content.Context; import android.content.Context;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference; import androidx.preference.Preference;
@@ -31,6 +33,7 @@ import androidx.preference.SwitchPreference;
import com.android.settings.R; import com.android.settings.R;
import com.android.settingslib.bluetooth.A2dpProfile; import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LeAudioProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfile; import com.android.settingslib.bluetooth.LocalBluetoothProfile;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -39,7 +42,10 @@ import com.android.settingslib.bluetooth.PanProfile;
import com.android.settingslib.bluetooth.PbapServerProfile; import com.android.settingslib.bluetooth.PbapServerProfile;
import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* This class adds switches for toggling the individual profiles that a Bluetooth device * This class adds switches for toggling the individual profiles that a Bluetooth device
@@ -48,8 +54,11 @@ import java.util.List;
public class BluetoothDetailsProfilesController extends BluetoothDetailsController public class BluetoothDetailsProfilesController extends BluetoothDetailsController
implements Preference.OnPreferenceClickListener, implements Preference.OnPreferenceClickListener,
LocalBluetoothProfileManager.ServiceListener { LocalBluetoothProfileManager.ServiceListener {
private static final String TAG = "BtDetailsProfilesCtrl";
private static final String KEY_PROFILES_GROUP = "bluetooth_profiles"; private static final String KEY_PROFILES_GROUP = "bluetooth_profiles";
private static final String KEY_BOTTOM_PREFERENCE = "bottom_preference"; private static final String KEY_BOTTOM_PREFERENCE = "bottom_preference";
private static final String HEADSET_CLIENT = "HEADSET_CLIENT";
private static final int ORDINAL = 99; private static final int ORDINAL = 99;
@VisibleForTesting @VisibleForTesting
@@ -58,6 +67,9 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
private LocalBluetoothManager mManager; private LocalBluetoothManager mManager;
private LocalBluetoothProfileManager mProfileManager; private LocalBluetoothProfileManager mProfileManager;
private CachedBluetoothDevice mCachedDevice; private CachedBluetoothDevice mCachedDevice;
private List<CachedBluetoothDevice> mAllOfCachedDevices;
private Map<String, List<CachedBluetoothDevice>> mProfileDeviceMap =
new HashMap<String, List<CachedBluetoothDevice>>();
@VisibleForTesting @VisibleForTesting
PreferenceCategory mProfilesContainer; PreferenceCategory mProfilesContainer;
@@ -68,6 +80,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
mManager = manager; mManager = manager;
mProfileManager = mManager.getProfileManager(); mProfileManager = mManager.getProfileManager();
mCachedDevice = device; mCachedDevice = device;
mAllOfCachedDevices = getAllOfCachedBluetoothDevices();
lifecycle.addObserver(this); lifecycle.addObserver(this);
} }
@@ -100,11 +113,66 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
/** /**
* Refreshes the state for an existing SwitchPreference for a profile. * Refreshes the state for an existing SwitchPreference for a profile.
* If the LeAudio profile is enabled on the LeAudio devices, then the SwitchPreferences of
* A2dp profile and Hfp profile are graied out.
*/ */
private void refreshProfilePreference(SwitchPreference profilePref, private void refreshProfilePreference(SwitchPreference profilePref,
LocalBluetoothProfile profile) { LocalBluetoothProfile profile) {
BluetoothDevice device = mCachedDevice.getDevice(); BluetoothDevice device = mCachedDevice.getDevice();
boolean isLeAudioEnabled = false;
if (profile instanceof A2dpProfile || HEADSET_CLIENT.equals(profile.toString())) {
LocalBluetoothProfile leAudio = mProfileManager.getLeAudioProfile();
if (leAudio != null) {
List<CachedBluetoothDevice> leAudioDeviceList = mProfileDeviceMap.get(
leAudio.toString());
if (leAudioDeviceList != null
&& leAudioDeviceList.stream()
.anyMatch(item -> leAudio.isEnabled(item.getDevice()))) {
isLeAudioEnabled = true;
}
}
if (isLeAudioEnabled) {
// If the LeAudio profile is enabled on the LeAudio devices, then the
// SwitchPreferences of A2dp profile and Hfp profile are graied out.
profilePref.setEnabled(false);
} else {
List<CachedBluetoothDevice> deviceList = mProfileDeviceMap.get(
profile.toString());
boolean isBusy = deviceList != null
&& deviceList.stream().anyMatch(item -> item.isBusy());
profilePref.setEnabled(!isBusy);
}
} else if (profile instanceof LeAudioProfile) {
List<CachedBluetoothDevice> leAudioDeviceList = mProfileDeviceMap.get(
profile.toString());
boolean isLeAudioProfileEnable =
leAudioDeviceList != null && leAudioDeviceList.stream().anyMatch(
item -> profile.isEnabled(item.getDevice()));
boolean isBusy = leAudioDeviceList != null
&& leAudioDeviceList.stream().anyMatch(item -> item.isBusy());
if (isLeAudioProfileEnable && !isBusy) {
LocalBluetoothProfile a2dp = mProfileManager.getA2dpProfile();
LocalBluetoothProfile hfp = mProfileManager.getHfpClientProfile();
// If the LeAudio profile is enabled on the LeAudio devices, then the
// SwitchPreferences of A2dp profile and Hfp profile are graied out.
if (a2dp != null) {
SwitchPreference pref = mProfilesContainer.findPreference(a2dp.toString());
if (pref != null) {
pref.setEnabled(false);
}
}
if (hfp != null) {
SwitchPreference pref = mProfilesContainer.findPreference(hfp.toString());
if (pref != null) {
pref.setEnabled(false);
}
}
}
profilePref.setEnabled(!isBusy);
} else {
profilePref.setEnabled(!mCachedDevice.isBusy()); profilePref.setEnabled(!mCachedDevice.isBusy());
}
if (profile instanceof MapProfile) { if (profile instanceof MapProfile) {
profilePref.setChecked(device.getMessageAccessPermission() profilePref.setChecked(device.getMessageAccessPermission()
== BluetoothDevice.ACCESS_ALLOWED); == BluetoothDevice.ACCESS_ALLOWED);
@@ -127,7 +195,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
highQualityPref.setVisible(true); highQualityPref.setVisible(true);
highQualityPref.setTitle(a2dp.getHighQualityAudioOptionLabel(device)); highQualityPref.setTitle(a2dp.getHighQualityAudioOptionLabel(device));
highQualityPref.setChecked(a2dp.isHighQualityAudioEnabled(device)); highQualityPref.setChecked(a2dp.isHighQualityAudioEnabled(device));
highQualityPref.setEnabled(!mCachedDevice.isBusy()); highQualityPref.setEnabled(!mCachedDevice.isBusy() && !isLeAudioEnabled);
} else { } else {
highQualityPref.setVisible(false); highQualityPref.setVisible(false);
} }
@@ -148,6 +216,12 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
if (profile instanceof MapProfile) { if (profile instanceof MapProfile) {
bluetoothDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED); bluetoothDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
} }
if (profile instanceof LeAudioProfile) {
enableLeAudioProfile(profile);
return;
}
profile.setEnabled(bluetoothDevice, true); profile.setEnabled(bluetoothDevice, true);
} }
@@ -155,8 +229,14 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
* Helper method to disable a profile for a device * Helper method to disable a profile for a device
*/ */
private void disableProfile(LocalBluetoothProfile profile) { private void disableProfile(LocalBluetoothProfile profile) {
if (profile instanceof LeAudioProfile) {
disableLeAudioProfile(profile);
return;
}
final BluetoothDevice bluetoothDevice = mCachedDevice.getDevice(); final BluetoothDevice bluetoothDevice = mCachedDevice.getDevice();
profile.setEnabled(bluetoothDevice, false); profile.setEnabled(bluetoothDevice, false);
if (profile instanceof MapProfile) { if (profile instanceof MapProfile) {
bluetoothDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED); bluetoothDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED);
} else if (profile instanceof PbapServerProfile) { } else if (profile instanceof PbapServerProfile) {
@@ -190,14 +270,33 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
return true; return true;
} }
/** /**
* Helper to get the list of connectable and special profiles. * Helper to get the list of connectable and special profiles.
*/ */
private List<LocalBluetoothProfile> getProfiles() { private List<LocalBluetoothProfile> getProfiles() {
List<LocalBluetoothProfile> result = mCachedDevice.getConnectableProfiles(); List<LocalBluetoothProfile> result = new ArrayList<LocalBluetoothProfile>();
final BluetoothDevice device = mCachedDevice.getDevice(); mProfileDeviceMap.clear();
if (mAllOfCachedDevices == null || mAllOfCachedDevices.isEmpty()) {
return result;
}
for (CachedBluetoothDevice cachedItem : mAllOfCachedDevices) {
List<LocalBluetoothProfile> tmpResult = cachedItem.getConnectableProfiles();
for (LocalBluetoothProfile profile : tmpResult) {
if (mProfileDeviceMap.containsKey(profile.toString())) {
mProfileDeviceMap.get(profile.toString()).add(cachedItem);
Log.d(TAG, "getProfiles: " + profile.toString() + " add device "
+ cachedItem.getDevice().getAnonymizedAddress());
} else {
List<CachedBluetoothDevice> tmpCachedDeviceList =
new ArrayList<CachedBluetoothDevice>();
tmpCachedDeviceList.add(cachedItem);
mProfileDeviceMap.put(profile.toString(), tmpCachedDeviceList);
result.add(profile);
}
}
}
final BluetoothDevice device = mCachedDevice.getDevice();
final int pbapPermission = device.getPhonebookAccessPermission(); final int pbapPermission = device.getPhonebookAccessPermission();
// Only provide PBAP cabability if the client device has requested PBAP. // Only provide PBAP cabability if the client device has requested PBAP.
if (pbapPermission != BluetoothDevice.ACCESS_UNKNOWN) { if (pbapPermission != BluetoothDevice.ACCESS_UNKNOWN) {
@@ -210,10 +309,93 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
if (mapPermission != BluetoothDevice.ACCESS_UNKNOWN) { if (mapPermission != BluetoothDevice.ACCESS_UNKNOWN) {
result.add(mapProfile); result.add(mapProfile);
} }
Log.d(TAG, "getProfiles:result:" + result);
return result; return result;
} }
private List<CachedBluetoothDevice> getAllOfCachedBluetoothDevices() {
List<CachedBluetoothDevice> cachedBluetoothDevices = new ArrayList<>();
if (mCachedDevice == null) {
return cachedBluetoothDevices;
}
cachedBluetoothDevices.add(mCachedDevice);
if (mCachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
for (CachedBluetoothDevice member : mCachedDevice.getMemberDevice()) {
cachedBluetoothDevices.add(member);
}
}
return cachedBluetoothDevices;
}
/**
* When user disable the Le Audio profile, the system needs to do two things.
* 1) Disable the Le Audio profile for each of the Le Audio devices.
* 2) Enable the A2dp profile and Hfp profile for the associated device. The system can't
* enable the A2dp profile and Hfp profile if the Le Audio profile is enabled.
*
* @param profile the LeAudio profile
*/
private void disableLeAudioProfile(LocalBluetoothProfile profile) {
if (profile == null || mProfileDeviceMap.get(profile.toString()) == null) {
Log.e(TAG, "There is no the LE profile or no device in mProfileDeviceMap. Do nothing.");
return;
}
for (CachedBluetoothDevice leAudioDevice : mProfileDeviceMap.get(profile.toString())) {
profile.setEnabled(leAudioDevice.getDevice(), false);
}
LocalBluetoothProfile a2dp = mProfileManager.getA2dpProfile();
LocalBluetoothProfile hfp = mProfileManager.getHfpClientProfile();
if (a2dp != null && mProfileDeviceMap.get(a2dp.toString()) != null) {
for (CachedBluetoothDevice a2dpDevice : mProfileDeviceMap.get(a2dp.toString())) {
if (!a2dp.isEnabled(a2dpDevice.getDevice())) {
a2dp.setEnabled(a2dpDevice.getDevice(), true);
}
}
}
if (hfp != null && mProfileDeviceMap.get(hfp.toString()) != null) {
for (CachedBluetoothDevice hfpDevice : mProfileDeviceMap.get(hfp.toString())) {
if (!hfp.isEnabled(hfpDevice.getDevice())) {
hfp.setEnabled(hfpDevice.getDevice(), true);
}
}
}
}
/**
* When user enable the Le Audio profile, the system needs to do two things.
* 1) Disable the A2dp profile and Hfp profile for the associated device. The system can't
* enable the Le Audio if the A2dp profile and Hfp profile are enabled.
* 2) Enable the Le Audio profile for each of the Le Audio devices.
*
* @param profile the LeAudio profile
*/
private void enableLeAudioProfile(LocalBluetoothProfile profile) {
if (profile == null || mProfileDeviceMap.get(profile.toString()) == null) {
Log.e(TAG, "There is no the LE profile or no device in mProfileDeviceMap. Do nothing.");
return;
}
LocalBluetoothProfile a2dp = mProfileManager.getA2dpProfile();
LocalBluetoothProfile hfp = mProfileManager.getHfpClientProfile();
if (a2dp != null && mProfileDeviceMap.get(a2dp.toString()) != null) {
for (CachedBluetoothDevice a2dpDevice : mProfileDeviceMap.get(a2dp.toString())) {
if (a2dp.isEnabled(a2dpDevice.getDevice())) {
a2dp.setEnabled(a2dpDevice.getDevice(), false);
}
}
}
if (hfp != null && mProfileDeviceMap.get(hfp.toString()) != null) {
for (CachedBluetoothDevice hfpDevice : mProfileDeviceMap.get(hfp.toString())) {
if (hfp.isEnabled(hfpDevice.getDevice())) {
hfp.setEnabled(hfpDevice.getDevice(), false);
}
}
}
for (CachedBluetoothDevice leAudioDevice : mProfileDeviceMap.get(profile.toString())) {
profile.setEnabled(leAudioDevice.getDevice(), true);
}
}
/** /**
* This is a helper method to be called after adding a Preference for a profile. If that * This is a helper method to be called after adding a Preference for a profile. If that
* profile happened to be A2dp and the device supports high quality audio, it will add a * profile happened to be A2dp and the device supports high quality audio, it will add a
@@ -243,16 +425,33 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); for (CachedBluetoothDevice item : mAllOfCachedDevices) {
item.unregisterCallback(this);
}
mProfileManager.removeServiceListener(this); mProfileManager.removeServiceListener(this);
} }
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); for (CachedBluetoothDevice item : mAllOfCachedDevices) {
item.registerCallback(this);
}
mProfileManager.addServiceListener(this); mProfileManager.addServiceListener(this);
} }
@Override
public void onDeviceAttributesChanged() {
for (CachedBluetoothDevice item : mAllOfCachedDevices) {
item.unregisterCallback(this);
}
mAllOfCachedDevices = getAllOfCachedBluetoothDevices();
for (CachedBluetoothDevice item : mAllOfCachedDevices) {
item.registerCallback(this);
}
super.onDeviceAttributesChanged();
}
@Override @Override
public void onServiceConnected() { public void onServiceConnected() {
refresh(); refresh();

View File

@@ -117,6 +117,7 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
return; return;
} }
use(AdvancedBluetoothDetailsHeaderController.class).init(mCachedDevice); use(AdvancedBluetoothDetailsHeaderController.class).init(mCachedDevice);
use(LeAudioBluetoothDetailsHeaderController.class).init(mCachedDevice, mManager);
final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory( final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(
context).getBluetoothFeatureProvider(context); context).getBluetoothFeatureProvider(context);

View File

@@ -0,0 +1,323 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.bluetooth;
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.util.Pair;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.fuelgauge.BatteryMeterView;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LeAudioProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnDestroy;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settingslib.widget.LayoutPreference;
import java.util.ArrayList;
import java.util.List;
/**
* This class adds a header with device name and status (connected/disconnected, etc.).
*/
public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceController implements
LifecycleObserver, OnStart, OnStop, OnDestroy, CachedBluetoothDevice.Callback {
private static final String TAG = "LeAudioBtHeaderCtrl";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@VisibleForTesting
static final int LEFT_DEVICE_ID =
BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT
| BluetoothLeAudio.AUDIO_LOCATION_BACK_LEFT
| BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT_OF_CENTER
| BluetoothLeAudio.AUDIO_LOCATION_SIDE_LEFT
| BluetoothLeAudio.AUDIO_LOCATION_TOP_FRONT_LEFT
| BluetoothLeAudio.AUDIO_LOCATION_TOP_BACK_LEFT
| BluetoothLeAudio.AUDIO_LOCATION_TOP_SIDE_LEFT
| BluetoothLeAudio.AUDIO_LOCATION_BOTTOM_FRONT_LEFT
| BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT_WIDE
| BluetoothLeAudio.AUDIO_LOCATION_LEFT_SURROUND;
@VisibleForTesting
static final int RIGHT_DEVICE_ID =
BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT
| BluetoothLeAudio.AUDIO_LOCATION_BACK_RIGHT
| BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER
| BluetoothLeAudio.AUDIO_LOCATION_SIDE_RIGHT
| BluetoothLeAudio.AUDIO_LOCATION_TOP_FRONT_RIGHT
| BluetoothLeAudio.AUDIO_LOCATION_TOP_BACK_RIGHT
| BluetoothLeAudio.AUDIO_LOCATION_TOP_SIDE_RIGHT
| BluetoothLeAudio.AUDIO_LOCATION_BOTTOM_FRONT_RIGHT
| BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT_WIDE
| BluetoothLeAudio.AUDIO_LOCATION_RIGHT_SURROUND;
@VisibleForTesting
static final int INVALID_RESOURCE_ID = -1;
@VisibleForTesting
LayoutPreference mLayoutPreference;
private CachedBluetoothDevice mCachedDevice;
@VisibleForTesting
Handler mHandler = new Handler(Looper.getMainLooper());
@VisibleForTesting
boolean mIsRegisterCallback = false;
private LocalBluetoothProfileManager mProfileManager;
public LeAudioBluetoothDetailsHeaderController(Context context, String prefKey) {
super(context, prefKey);
}
@Override
public int getAvailabilityStatus() {
if (mCachedDevice == null || mProfileManager == null) {
return CONDITIONALLY_UNAVAILABLE;
}
boolean hasLeAudio = mCachedDevice.getConnectableProfiles()
.stream()
.anyMatch(profile -> profile.getProfileId() == BluetoothProfile.LE_AUDIO);
return !Utils.isAdvancedDetailsHeader(mCachedDevice.getDevice()) && hasLeAudio
? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mLayoutPreference = screen.findPreference(getPreferenceKey());
mLayoutPreference.setVisible(isAvailable());
}
@Override
public void onStart() {
if (!isAvailable()) {
return;
}
mIsRegisterCallback = true;
mCachedDevice.registerCallback(this);
refresh();
}
@Override
public void onStop() {
if (!mIsRegisterCallback) {
return;
}
mCachedDevice.unregisterCallback(this);
mIsRegisterCallback = false;
}
@Override
public void onDestroy() {
}
public void init(CachedBluetoothDevice cachedBluetoothDevice,
LocalBluetoothManager bluetoothManager) {
mCachedDevice = cachedBluetoothDevice;
mProfileManager = bluetoothManager.getProfileManager();
}
@VisibleForTesting
void refresh() {
if (mLayoutPreference == null || mCachedDevice == null) {
return;
}
final ImageView imageView = mLayoutPreference.findViewById(R.id.entity_header_icon);
if (imageView != null) {
final Pair<Drawable, String> pair =
BluetoothUtils.getBtRainbowDrawableWithDescription(mContext, mCachedDevice);
imageView.setImageDrawable(pair.first);
imageView.setContentDescription(pair.second);
}
final TextView title = mLayoutPreference.findViewById(R.id.entity_header_title);
if (title != null) {
title.setText(mCachedDevice.getName());
}
final TextView summary = mLayoutPreference.findViewById(R.id.entity_header_summary);
if (summary != null) {
summary.setText(mCachedDevice.getConnectionSummary(true /* shortSummary */));
}
if (!mCachedDevice.isConnected() || mCachedDevice.isBusy()) {
hideAllOfBatteryLayouts();
return;
}
updateBatteryLayout();
}
@VisibleForTesting
Drawable createBtBatteryIcon(Context context, int level) {
final BatteryMeterView.BatteryMeterDrawable drawable =
new BatteryMeterView.BatteryMeterDrawable(context,
context.getColor(R.color.meter_background_color),
context.getResources().getDimensionPixelSize(
R.dimen.advanced_bluetooth_battery_meter_width),
context.getResources().getDimensionPixelSize(
R.dimen.advanced_bluetooth_battery_meter_height));
drawable.setBatteryLevel(level);
drawable.setColorFilter(new PorterDuffColorFilter(
com.android.settings.Utils.getColorAttrDefaultColor(context,
android.R.attr.colorControlNormal),
PorterDuff.Mode.SRC));
return drawable;
}
private int getBatteryTitleResource(int deviceId) {
if (deviceId == LEFT_DEVICE_ID) {
return R.id.bt_battery_left_title;
}
if (deviceId == RIGHT_DEVICE_ID) {
return R.id.bt_battery_right_title;
}
Log.d(TAG, "No resource id. The deviceId is " + deviceId);
return INVALID_RESOURCE_ID;
}
private int getBatterySummaryResource(int deviceId) {
if (deviceId == LEFT_DEVICE_ID) {
return R.id.bt_battery_left_summary;
}
if (deviceId == RIGHT_DEVICE_ID) {
return R.id.bt_battery_right_summary;
}
Log.d(TAG, "No resource id. The deviceId is " + deviceId);
return INVALID_RESOURCE_ID;
}
private void hideAllOfBatteryLayouts() {
// hide the case
updateBatteryLayout(R.id.bt_battery_case_title, R.id.bt_battery_case_summary,
BluetoothUtils.META_INT_ERROR);
// hide the left
updateBatteryLayout(R.id.bt_battery_left_title, R.id.bt_battery_left_summary,
BluetoothUtils.META_INT_ERROR);
// hide the right
updateBatteryLayout(R.id.bt_battery_right_title, R.id.bt_battery_right_summary,
BluetoothUtils.META_INT_ERROR);
}
private List<CachedBluetoothDevice> getAllOfLeAudioDevices() {
if (mCachedDevice == null) {
return null;
}
List<CachedBluetoothDevice> leAudioDevices = new ArrayList<>();
leAudioDevices.add(mCachedDevice);
if (mCachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
for (CachedBluetoothDevice member : mCachedDevice.getMemberDevice()) {
leAudioDevices.add(member);
}
}
return leAudioDevices;
}
private void updateBatteryLayout() {
// Init the battery layouts.
hideAllOfBatteryLayouts();
final List<CachedBluetoothDevice> leAudioDevices = getAllOfLeAudioDevices();
LeAudioProfile leAudioProfile = mProfileManager.getLeAudioProfile();
if (leAudioDevices == null || leAudioDevices.isEmpty()) {
Log.e(TAG, "There is no LeAudioProfile.");
return;
}
if (!leAudioProfile.isEnabled(mCachedDevice.getDevice())) {
Log.d(TAG, "Show the legacy battery style if the LeAudio is not enabled.");
final TextView summary = mLayoutPreference.findViewById(R.id.entity_header_summary);
if (summary != null) {
summary.setText(mCachedDevice.getConnectionSummary());
}
return;
}
for (CachedBluetoothDevice cachedDevice : leAudioDevices) {
int deviceId = leAudioProfile.getAudioLocation(cachedDevice.getDevice());
Log.d(TAG, "LeAudioDevices:" + cachedDevice.getDevice().getAnonymizedAddress()
+ ", deviceId:" + deviceId);
if (deviceId == BluetoothLeAudio.AUDIO_LOCATION_INVALID) {
Log.d(TAG, "The device does not support the AUDIO_LOCATION.");
return;
}
boolean isLeft = (deviceId & LEFT_DEVICE_ID) != 0;
boolean isRight = (deviceId & LEFT_DEVICE_ID) != 0;
boolean isLeftRight = isLeft && isRight;
// The LE device updates the BatteryLayout
if (isLeftRight) {
Log.d(TAG, "The device id is left+right. Do nothing.");
} else if (isLeft) {
updateBatteryLayout(getBatteryTitleResource(LEFT_DEVICE_ID),
getBatterySummaryResource(LEFT_DEVICE_ID), cachedDevice.getBatteryLevel());
} else if (isRight) {
updateBatteryLayout(getBatteryTitleResource(RIGHT_DEVICE_ID),
getBatterySummaryResource(RIGHT_DEVICE_ID), cachedDevice.getBatteryLevel());
} else {
Log.d(TAG, "The device id is other Audio Location. Do nothing.");
}
}
}
private void updateBatteryLayout(int titleResId, int summaryResId, int batteryLevel) {
final TextView batteryTitleView = mLayoutPreference.findViewById(titleResId);
final TextView batterySummaryView = mLayoutPreference.findViewById(summaryResId);
if (batteryTitleView == null || batterySummaryView == null) {
Log.e(TAG, "updateBatteryLayout: No TextView");
return;
}
if (batteryLevel != BluetoothUtils.META_INT_ERROR) {
batteryTitleView.setVisibility(View.VISIBLE);
batterySummaryView.setVisibility(View.VISIBLE);
batterySummaryView.setText(
com.android.settings.Utils.formatPercentage(batteryLevel));
batterySummaryView.setCompoundDrawablesRelativeWithIntrinsicBounds(
createBtBatteryIcon(mContext, batteryLevel), /* top */ null,
/* end */ null, /* bottom */ null);
} else {
Log.d(TAG, "updateBatteryLayout: Hide it if it doesn't have battery information.");
batteryTitleView.setVisibility(View.GONE);
batterySummaryView.setVisibility(View.GONE);
}
}
@Override
public void onDeviceAttributesChanged() {
if (mCachedDevice != null) {
refresh();
}
}
}

View File

@@ -505,7 +505,6 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new HdcpCheckingPreferenceController(context)); controllers.add(new HdcpCheckingPreferenceController(context));
controllers.add(new BluetoothSnoopLogPreferenceController(context)); controllers.add(new BluetoothSnoopLogPreferenceController(context));
controllers.add(new OemUnlockPreferenceController(context, activity, fragment)); controllers.add(new OemUnlockPreferenceController(context, activity, fragment));
controllers.add(new FileEncryptionPreferenceController(context));
controllers.add(new PictureColorModePreferenceController(context, lifecycle)); controllers.add(new PictureColorModePreferenceController(context, lifecycle));
controllers.add(new WebViewAppPreferenceController(context)); controllers.add(new WebViewAppPreferenceController(context));
controllers.add(new CoolColorTemperaturePreferenceController(context)); controllers.add(new CoolColorTemperaturePreferenceController(context));

View File

@@ -1,85 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.development;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.storage.IStorageManager;
import android.text.TextUtils;
import android.sysprop.CryptoProperties;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
public class FileEncryptionPreferenceController extends DeveloperOptionsPreferenceController
implements PreferenceControllerMixin {
private static final String KEY_CONVERT_FBE = "convert_to_file_encryption";
private static final String KEY_STORAGE_MANAGER = "mount";
private final IStorageManager mStorageManager;
public FileEncryptionPreferenceController(Context context) {
super(context);
mStorageManager = getStorageManager();
}
@Override
public boolean isAvailable() {
if (mStorageManager == null) {
return false;
}
try {
return mStorageManager.isConvertibleToFBE();
} catch (RemoteException e) {
return false;
}
}
@Override
public String getPreferenceKey() {
return KEY_CONVERT_FBE;
}
@Override
public void updateState(Preference preference) {
if (CryptoProperties.type().orElse(CryptoProperties.type_values.NONE) !=
CryptoProperties.type_values.FILE) {
return;
}
mPreference.setEnabled(false);
mPreference.setSummary(
mContext.getResources().getString(R.string.convert_to_file_encryption_done));
}
private IStorageManager getStorageManager() {
try {
return IStorageManager.Stub.asInterface(
ServiceManager.getService(KEY_STORAGE_MANAGER));
} catch (VerifyError e) {
// Used for tests since Robolectric cannot initialize this class.
return null;
}
}
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.deviceinfo; package com.android.settings.deviceinfo;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context; import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.ProgressBar; import android.widget.ProgressBar;
@@ -30,6 +32,7 @@ public class StorageItemPreference extends Preference {
public int userHandle; public int userHandle;
private static final int UNINITIALIZED = -1; private static final int UNINITIALIZED = -1;
private static final int ANIMATE_DURATION_IN_MILLIS = 1000;
private ProgressBar mProgressBar; private ProgressBar mProgressBar;
private static final int PROGRESS_MAX = 100; private static final int PROGRESS_MAX = 100;
@@ -46,15 +49,33 @@ public class StorageItemPreference extends Preference {
} }
public void setStorageSize(long size, long total) { public void setStorageSize(long size, long total) {
mStorageSize = size; setStorageSize(size, total, false /* animate */);
setSummary(StorageUtils.getStorageSizeLabel(getContext(), size));
if (total == 0) {
mProgressPercent = 0;
} else {
mProgressPercent = (int)(size * PROGRESS_MAX / total);
} }
updateProgressBar();
/**
* Set the storage size info with/without animation
*/
public void setStorageSize(long size, long total, boolean animate) {
if (animate) {
TypeEvaluator<Long> longEvaluator =
(fraction, startValue, endValue) -> {
// Directly returns end value if fraction is 1.0 and the end value is 0.
if (fraction >= 1.0f && endValue == 0) {
return endValue;
}
return startValue + (long) (fraction * (endValue - startValue));
};
ValueAnimator valueAnimator = ValueAnimator.ofObject(longEvaluator, mStorageSize, size);
valueAnimator.setDuration(ANIMATE_DURATION_IN_MILLIS);
valueAnimator.addUpdateListener(
animation -> {
updateProgressBarAndSizeInfo((long) animation.getAnimatedValue(), total);
});
valueAnimator.start();
} else {
updateProgressBarAndSizeInfo(size, total);
}
mStorageSize = size;
} }
public long getStorageSize() { public long getStorageSize() {
@@ -62,11 +83,18 @@ public class StorageItemPreference extends Preference {
} }
protected void updateProgressBar() { protected void updateProgressBar() {
if (mProgressBar == null || mProgressPercent == UNINITIALIZED) if (mProgressBar == null || mProgressPercent == UNINITIALIZED) {
return; return;
}
mProgressBar.setMax(PROGRESS_MAX); mProgressBar.setMax(PROGRESS_MAX);
mProgressBar.setProgress(mProgressPercent, true /* animate */); mProgressBar.setProgress(mProgressPercent);
}
private void updateProgressBarAndSizeInfo(long size, long total) {
setSummary(StorageUtils.getStorageSizeLabel(getContext(), size));
mProgressPercent = total == 0 ? 0 : (int) (size * PROGRESS_MAX / total);
updateProgressBar();
} }
@Override @Override

View File

@@ -378,18 +378,22 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
*/ */
public void onLoadFinished(@Nullable SparseArray<StorageAsyncLoader.StorageResult> result, public void onLoadFinished(@Nullable SparseArray<StorageAsyncLoader.StorageResult> result,
int userId) { int userId) {
// Enable animation when the storage size info is from StorageAsyncLoader whereas disable
// animation when the cached storage size info is used instead.
boolean animate = result != null && mIsPreferenceOrderedBySize;
// Calculate the size info for each category // Calculate the size info for each category
StorageCacheHelper.StorageCache storageCache = getSizeInfo(result, userId); StorageCacheHelper.StorageCache storageCache = getSizeInfo(result, userId);
// Set size info to each preference // Set size info to each preference
mImagesPreference.setStorageSize(storageCache.imagesSize, mTotalSize); mImagesPreference.setStorageSize(storageCache.imagesSize, mTotalSize, animate);
mVideosPreference.setStorageSize(storageCache.videosSize, mTotalSize); mVideosPreference.setStorageSize(storageCache.videosSize, mTotalSize, animate);
mAudioPreference.setStorageSize(storageCache.audioSize, mTotalSize); mAudioPreference.setStorageSize(storageCache.audioSize, mTotalSize, animate);
mAppsPreference.setStorageSize(storageCache.allAppsExceptGamesSize, mTotalSize); mAppsPreference.setStorageSize(storageCache.allAppsExceptGamesSize, mTotalSize, animate);
mGamesPreference.setStorageSize(storageCache.gamesSize, mTotalSize); mGamesPreference.setStorageSize(storageCache.gamesSize, mTotalSize, animate);
mDocumentsAndOtherPreference.setStorageSize(storageCache.documentsAndOtherSize, mTotalSize); mDocumentsAndOtherPreference.setStorageSize(storageCache.documentsAndOtherSize, mTotalSize,
mTrashPreference.setStorageSize(storageCache.trashSize, mTotalSize); animate);
mTrashPreference.setStorageSize(storageCache.trashSize, mTotalSize, animate);
if (mSystemPreference != null) { if (mSystemPreference != null) {
mSystemPreference.setStorageSize(storageCache.systemSize, mTotalSize); mSystemPreference.setStorageSize(storageCache.systemSize, mTotalSize, animate);
} }
// Cache the size info // Cache the size info
if (result != null) { if (result != null) {
@@ -519,7 +523,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
if (mTrashPreference == null) { if (mTrashPreference == null) {
return; return;
} }
mTrashPreference.setStorageSize(0, mTotalSize); mTrashPreference.setStorageSize(0, mTotalSize, true /* animate */);
updatePrivateStorageCategoryPreferencesOrder(); updatePrivateStorageCategoryPreferencesOrder();
} }

View File

@@ -182,6 +182,8 @@ public class SettingsHomepageActivity extends FragmentActivity implements
showSuggestionFragment(scrollNeeded); showSuggestionFragment(scrollNeeded);
if (FeatureFlagUtils.isEnabled(this, FeatureFlags.CONTEXTUAL_HOME)) { if (FeatureFlagUtils.isEnabled(this, FeatureFlags.CONTEXTUAL_HOME)) {
showFragment(() -> new ContextualCardsFragment(), R.id.contextual_cards_content); showFragment(() -> new ContextualCardsFragment(), R.id.contextual_cards_content);
((FrameLayout) findViewById(R.id.main_content))
.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
} }
} }
mMainFragment = showFragment(() -> { mMainFragment = showFragment(() -> {
@@ -191,9 +193,6 @@ public class SettingsHomepageActivity extends FragmentActivity implements
return fragment; return fragment;
}, R.id.main_content); }, R.id.main_content);
((FrameLayout) findViewById(R.id.main_content))
.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
// Launch the intent from deep link for large screen devices. // Launch the intent from deep link for large screen devices.
launchDeepLinkIntentToRight(); launchDeepLinkIntentToRight();
} }

View File

@@ -23,7 +23,6 @@ import android.os.Parcelable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@@ -43,14 +42,17 @@ public class TopLevelHighlightMixin implements Parcelable, DialogInterface.OnSho
private String mHiddenKey; private String mHiddenKey;
private DialogInterface mDialog; private DialogInterface mDialog;
private HighlightableTopLevelPreferenceAdapter mTopLevelAdapter; private HighlightableTopLevelPreferenceAdapter mTopLevelAdapter;
private boolean mActivityEmbedded;
public TopLevelHighlightMixin() { public TopLevelHighlightMixin(boolean activityEmbedded) {
mActivityEmbedded = activityEmbedded;
} }
public TopLevelHighlightMixin(Parcel source) { public TopLevelHighlightMixin(Parcel source) {
mCurrentKey = source.readString(); mCurrentKey = source.readString();
mPreviousKey = source.readString(); mPreviousKey = source.readString();
mHiddenKey = source.readString(); mHiddenKey = source.readString();
mActivityEmbedded = source.readBoolean();
} }
@Override @Override
@@ -58,6 +60,7 @@ public class TopLevelHighlightMixin implements Parcelable, DialogInterface.OnSho
dest.writeString(mCurrentKey); dest.writeString(mCurrentKey);
dest.writeString(mPreviousKey); dest.writeString(mPreviousKey);
dest.writeString(mHiddenKey); dest.writeString(mHiddenKey);
dest.writeBoolean(mActivityEmbedded);
} }
@Override @Override
@@ -96,8 +99,16 @@ public class TopLevelHighlightMixin implements Parcelable, DialogInterface.OnSho
} }
} }
void setActivityEmbedded(boolean activityEmbedded) {
mActivityEmbedded = activityEmbedded;
}
boolean isActivityEmbedded() {
return mActivityEmbedded;
}
RecyclerView.Adapter onCreateAdapter(TopLevelSettings topLevelSettings, RecyclerView.Adapter onCreateAdapter(TopLevelSettings topLevelSettings,
PreferenceScreen preferenceScreen) { PreferenceScreen preferenceScreen, boolean scrollNeeded) {
if (TextUtils.isEmpty(mCurrentKey)) { if (TextUtils.isEmpty(mCurrentKey)) {
mCurrentKey = getHighlightPrefKeyFromArguments(topLevelSettings.getArguments()); mCurrentKey = getHighlightPrefKeyFromArguments(topLevelSettings.getArguments());
} }
@@ -105,7 +116,7 @@ public class TopLevelHighlightMixin implements Parcelable, DialogInterface.OnSho
Log.d(TAG, "onCreateAdapter, pref key: " + mCurrentKey); Log.d(TAG, "onCreateAdapter, pref key: " + mCurrentKey);
mTopLevelAdapter = new HighlightableTopLevelPreferenceAdapter( mTopLevelAdapter = new HighlightableTopLevelPreferenceAdapter(
(SettingsHomepageActivity) topLevelSettings.getActivity(), preferenceScreen, (SettingsHomepageActivity) topLevelSettings.getActivity(), preferenceScreen,
topLevelSettings.getListView(), mCurrentKey); topLevelSettings.getListView(), mCurrentKey, scrollNeeded);
return mTopLevelAdapter; return mTopLevelAdapter;
} }
@@ -129,7 +140,7 @@ public class TopLevelHighlightMixin implements Parcelable, DialogInterface.OnSho
} }
} }
void highlightPreferenceIfNeeded(FragmentActivity activity) { void highlightPreferenceIfNeeded() {
if (mTopLevelAdapter != null) { if (mTopLevelAdapter != null) {
mTopLevelAdapter.requestHighlight(); mTopLevelAdapter.requestHighlight();
} }

View File

@@ -58,6 +58,7 @@ public class TopLevelSettings extends DashboardFragment implements
private boolean mIsEmbeddingActivityEnabled; private boolean mIsEmbeddingActivityEnabled;
private TopLevelHighlightMixin mHighlightMixin; private TopLevelHighlightMixin mHighlightMixin;
private boolean mScrollNeeded = true;
private boolean mFirstStarted = true; private boolean mFirstStarted = true;
public TopLevelSettings() { public TopLevelSettings() {
@@ -133,11 +134,14 @@ public class TopLevelSettings extends DashboardFragment implements
return; return;
} }
boolean activityEmbedded = SplitController.getInstance().isActivityEmbedded(getActivity());
if (icicle != null) { if (icicle != null) {
mHighlightMixin = icicle.getParcelable(SAVED_HIGHLIGHT_MIXIN); mHighlightMixin = icicle.getParcelable(SAVED_HIGHLIGHT_MIXIN);
mScrollNeeded = !mHighlightMixin.isActivityEmbedded() && activityEmbedded;
mHighlightMixin.setActivityEmbedded(activityEmbedded);
} }
if (mHighlightMixin == null) { if (mHighlightMixin == null) {
mHighlightMixin = new TopLevelHighlightMixin(); mHighlightMixin = new TopLevelHighlightMixin(activityEmbedded);
} }
} }
@@ -201,7 +205,7 @@ public class TopLevelSettings extends DashboardFragment implements
@Override @Override
public void highlightPreferenceIfNeeded() { public void highlightPreferenceIfNeeded() {
if (mHighlightMixin != null) { if (mHighlightMixin != null) {
mHighlightMixin.highlightPreferenceIfNeeded(getActivity()); mHighlightMixin.highlightPreferenceIfNeeded();
} }
} }
@@ -243,7 +247,7 @@ public class TopLevelSettings extends DashboardFragment implements
if (!mIsEmbeddingActivityEnabled || !(getActivity() instanceof SettingsHomepageActivity)) { if (!mIsEmbeddingActivityEnabled || !(getActivity() instanceof SettingsHomepageActivity)) {
return super.onCreateAdapter(preferenceScreen); return super.onCreateAdapter(preferenceScreen);
} }
return mHighlightMixin.onCreateAdapter(this, preferenceScreen); return mHighlightMixin.onCreateAdapter(this, preferenceScreen, mScrollNeeded);
} }
@Override @Override

View File

@@ -251,6 +251,10 @@ public class EnabledNetworkModePreferenceController extends
} }
void setPreferenceEntries() { void setPreferenceEntries() {
mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId);
final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(mSubId);
final boolean display2gOptions = carrierConfig
.getBoolean(CarrierConfigManager.KEY_PREFER_2G_BOOL);
clearAllEntries(); clearAllEntries();
String[] entryValues; String[] entryValues;
int[] entryValuesInt; int[] entryValuesInt;
@@ -266,7 +270,9 @@ public class EnabledNetworkModePreferenceController extends
add5gEntry(addNrToLteNetworkType(entryValuesInt[0])); add5gEntry(addNrToLteNetworkType(entryValuesInt[0]));
addLteEntry(entryValuesInt[0]); addLteEntry(entryValuesInt[0]);
add3gEntry(entryValuesInt[1]); add3gEntry(entryValuesInt[1]);
if (display2gOptions) {
add1xEntry(entryValuesInt[2]); add1xEntry(entryValuesInt[2]);
}
addGlobalEntry(entryValuesInt[3]); addGlobalEntry(entryValuesInt[3]);
break; break;
case ENABLED_NETWORKS_CDMA_NO_LTE_CHOICES: case ENABLED_NETWORKS_CDMA_NO_LTE_CHOICES:
@@ -278,7 +284,9 @@ public class EnabledNetworkModePreferenceController extends
"ENABLED_NETWORKS_CDMA_NO_LTE_CHOICES index error."); "ENABLED_NETWORKS_CDMA_NO_LTE_CHOICES index error.");
} }
add3gEntry(entryValuesInt[0]); add3gEntry(entryValuesInt[0]);
if (display2gOptions) {
add1xEntry(entryValuesInt[1]); add1xEntry(entryValuesInt[1]);
}
break; break;
case ENABLED_NETWORKS_CDMA_ONLY_LTE_CHOICES: case ENABLED_NETWORKS_CDMA_ONLY_LTE_CHOICES:
entryValues = getResourcesForSubId().getStringArray( entryValues = getResourcesForSubId().getStringArray(
@@ -302,7 +310,9 @@ public class EnabledNetworkModePreferenceController extends
add5gEntry(addNrToLteNetworkType(entryValuesInt[0])); add5gEntry(addNrToLteNetworkType(entryValuesInt[0]));
addLteEntry(entryValuesInt[0]); addLteEntry(entryValuesInt[0]);
add3gEntry(entryValuesInt[1]); add3gEntry(entryValuesInt[1]);
if (display2gOptions) {
add2gEntry(entryValuesInt[2]); add2gEntry(entryValuesInt[2]);
}
break; break;
case ENABLED_NETWORKS_EXCEPT_GSM_LTE_CHOICES: case ENABLED_NETWORKS_EXCEPT_GSM_LTE_CHOICES:
entryValues = getResourcesForSubId().getStringArray( entryValues = getResourcesForSubId().getStringArray(
@@ -347,7 +357,9 @@ public class EnabledNetworkModePreferenceController extends
"ENABLED_NETWORKS_EXCEPT_LTE_CHOICES index error."); "ENABLED_NETWORKS_EXCEPT_LTE_CHOICES index error.");
} }
add3gEntry(entryValuesInt[0]); add3gEntry(entryValuesInt[0]);
if (carrierConfig.getBoolean(CarrierConfigManager.KEY_PREFER_2G_BOOL)) {
add2gEntry(entryValuesInt[1]); add2gEntry(entryValuesInt[1]);
}
break; break;
case ENABLED_NETWORKS_4G_CHOICES: case ENABLED_NETWORKS_4G_CHOICES:
entryValues = getResourcesForSubId().getStringArray( entryValues = getResourcesForSubId().getStringArray(
@@ -361,7 +373,9 @@ public class EnabledNetworkModePreferenceController extends
entryValuesInt[0])); entryValuesInt[0]));
add4gEntry(entryValuesInt[0]); add4gEntry(entryValuesInt[0]);
add3gEntry(entryValuesInt[1]); add3gEntry(entryValuesInt[1]);
if (display2gOptions) {
add2gEntry(entryValuesInt[2]); add2gEntry(entryValuesInt[2]);
}
break; break;
case ENABLED_NETWORKS_CHOICES: case ENABLED_NETWORKS_CHOICES:
entryValues = getResourcesForSubId().getStringArray( entryValues = getResourcesForSubId().getStringArray(
@@ -373,7 +387,9 @@ public class EnabledNetworkModePreferenceController extends
add5gEntry(addNrToLteNetworkType(entryValuesInt[0])); add5gEntry(addNrToLteNetworkType(entryValuesInt[0]));
addLteEntry(entryValuesInt[0]); addLteEntry(entryValuesInt[0]);
add3gEntry(entryValuesInt[1]); add3gEntry(entryValuesInt[1]);
if (display2gOptions) {
add2gEntry(entryValuesInt[2]); add2gEntry(entryValuesInt[2]);
}
break; break;
case PREFERRED_NETWORK_MODE_CHOICES_WORLD_MODE: case PREFERRED_NETWORK_MODE_CHOICES_WORLD_MODE:
entryValues = getResourcesForSubId().getStringArray( entryValues = getResourcesForSubId().getStringArray(

View File

@@ -26,6 +26,7 @@ import android.app.settings.SettingsEnums;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.safetycenter.SafetyCenterManager;
import android.safetycenter.SafetyEvent; import android.safetycenter.SafetyEvent;
import com.android.settings.security.ScreenLockPreferenceDetailsUtils; import com.android.settings.security.ScreenLockPreferenceDetailsUtils;
@@ -37,8 +38,6 @@ import java.util.List;
/** Broadcast receiver for handling requests from Safety Center for fresh data. */ /** Broadcast receiver for handling requests from Safety Center for fresh data. */
public class SafetySourceBroadcastReceiver extends BroadcastReceiver { public class SafetySourceBroadcastReceiver extends BroadcastReceiver {
private static final SafetyEvent EVENT_REFRESH_REQUESTED =
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED).build();
private static final SafetyEvent EVENT_DEVICE_REBOOTED = private static final SafetyEvent EVENT_DEVICE_REBOOTED =
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build(); new SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build();
@@ -52,10 +51,15 @@ public class SafetySourceBroadcastReceiver extends BroadcastReceiver {
String[] sourceIdsExtra = String[] sourceIdsExtra =
intent.getStringArrayExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS); intent.getStringArrayExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS);
if (sourceIdsExtra != null && sourceIdsExtra.length > 0) { if (sourceIdsExtra != null && sourceIdsExtra.length > 0) {
final String refreshBroadcastId = intent.getStringExtra(
SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID);
final SafetyEvent safetyEvent = new SafetyEvent.Builder(
SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
.setRefreshBroadcastId(refreshBroadcastId).build();
refreshSafetySources( refreshSafetySources(
context, context,
ImmutableList.copyOf(sourceIdsExtra), ImmutableList.copyOf(sourceIdsExtra),
EVENT_REFRESH_REQUESTED); safetyEvent);
} }
return; return;
} }

View File

@@ -67,10 +67,12 @@ public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapt
private SparseArray<PreferenceViewHolder> mViewHolders; private SparseArray<PreferenceViewHolder> mViewHolders;
public HighlightableTopLevelPreferenceAdapter(SettingsHomepageActivity homepageActivity, public HighlightableTopLevelPreferenceAdapter(SettingsHomepageActivity homepageActivity,
PreferenceGroup preferenceGroup, RecyclerView recyclerView, String key) { PreferenceGroup preferenceGroup, RecyclerView recyclerView, String key,
boolean scrollNeeded) {
super(preferenceGroup); super(preferenceGroup);
mRecyclerView = recyclerView; mRecyclerView = recyclerView;
mHighlightKey = key; mHighlightKey = key;
mScrolled = !scrollNeeded;
mViewHolders = new SparseArray<>(); mViewHolders = new SparseArray<>();
mContext = preferenceGroup.getContext(); mContext = preferenceGroup.getContext();
mHomepageActivity = homepageActivity; mHomepageActivity = homepageActivity;

View File

@@ -168,10 +168,18 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
break; break;
case MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS: case MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS:
final Context context = getContext();
if (context == null) {
// Context may be null if the message is received after the Activity has
// been destroyed
Log.d(TAG, "Scan success but context is null");
return;
}
// We may get 2 WifiConfiguration if the QR code has no password in it, // We may get 2 WifiConfiguration if the QR code has no password in it,
// one for open network and one for enhanced open network. // one for open network and one for enhanced open network.
final WifiManager wifiManager = final WifiManager wifiManager =
getContext().getSystemService(WifiManager.class); context.getSystemService(WifiManager.class);
final WifiNetworkConfig qrCodeWifiNetworkConfig = final WifiNetworkConfig qrCodeWifiNetworkConfig =
(WifiNetworkConfig)msg.obj; (WifiNetworkConfig)msg.obj;
final List<WifiConfiguration> qrCodeWifiConfigurations = final List<WifiConfiguration> qrCodeWifiConfigurations =

View File

@@ -124,6 +124,7 @@ public class QrCamera extends Handler {
} }
if (mCamera != null) { if (mCamera != null) {
mCamera.stopPreview(); mCamera.stopPreview();
releaseCamera();
} }
} }

View File

@@ -15,7 +15,6 @@ com.android.settings.applications.appinfo.ExternalSourcesDetails
com.android.settings.applications.appinfo.WriteSettingsDetails com.android.settings.applications.appinfo.WriteSettingsDetails
com.android.settings.applications.AppLaunchSettings com.android.settings.applications.AppLaunchSettings
com.android.settings.applications.AppStorageSettings com.android.settings.applications.AppStorageSettings
com.android.settings.applications.ConfirmConvertToFbe
com.android.settings.applications.ProcessStatsDetail com.android.settings.applications.ProcessStatsDetail
com.android.settings.applications.ProcessStatsSummary com.android.settings.applications.ProcessStatsSummary
com.android.settings.applications.ProcessStatsUi com.android.settings.applications.ProcessStatsUi

View File

@@ -121,4 +121,16 @@ public class AccessibilityFooterPreferenceControllerTest {
assertThat(learnMoreView.getVisibility()).isEqualTo(View.GONE); assertThat(learnMoreView.getVisibility()).isEqualTo(View.GONE);
assertThat(mPreference.isLinkEnabled()).isFalse(); assertThat(mPreference.isLinkEnabled()).isFalse();
} }
@Test
public void onBindViewHolder_setHelpResource_expectSummaryViewIsNonFocusable() {
mController.setupHelpLink(R.string.help_url_timeout, TEST_CONTENT_DESCRIPTION);
mController.displayPreference(mScreen);
mPreference.onBindViewHolder(mPreferenceViewHolder);
final TextView summaryView = (TextView) mPreferenceViewHolder
.findViewById(android.R.id.title);
assertThat(summaryView.isFocusable()).isFalse();
}
} }

View File

@@ -71,4 +71,15 @@ public final class AccessibilityFooterPreferenceTest {
android.R.id.title); android.R.id.title);
assertThat(summaryView.getMovementMethod()).isInstanceOf(MovementMethod.class); assertThat(summaryView.getMovementMethod()).isInstanceOf(MovementMethod.class);
} }
@Test
public void onBindViewHolder_setLinkEnabled_expectSummaryViewIsNonFocusable() {
mAccessibilityFooterPreference.setLinkEnabled(true);
mAccessibilityFooterPreference.onBindViewHolder(mPreferenceViewHolder);
final TextView summaryView = (TextView) mPreferenceViewHolder.findViewById(
android.R.id.title);
assertThat(summaryView.isFocusable()).isFalse();
}
} }

View File

@@ -322,7 +322,7 @@ public class ToggleFeaturePreferenceFragmentTest {
(AccessibilityFooterPreference) mFragment.getPreferenceScreen().getPreference( (AccessibilityFooterPreference) mFragment.getPreferenceScreen().getPreference(
mFragment.getPreferenceScreen().getPreferenceCount() - 1); mFragment.getPreferenceScreen().getPreferenceCount() - 1);
assertThat(accessibilityFooterPreference.getSummary()).isEqualTo(DEFAULT_SUMMARY); assertThat(accessibilityFooterPreference.getSummary()).isEqualTo(DEFAULT_SUMMARY);
assertThat(accessibilityFooterPreference.isSelectable()).isEqualTo(true); assertThat(accessibilityFooterPreference.isSelectable()).isEqualTo(false);
assertThat(accessibilityFooterPreference.getOrder()).isEqualTo(Integer.MAX_VALUE - 1); assertThat(accessibilityFooterPreference.getOrder()).isEqualTo(Integer.MAX_VALUE - 1);
} }

View File

@@ -1,116 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.development;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.RemoteException;
import android.os.storage.IStorageManager;
import android.sysprop.CryptoProperties;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
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;
import org.robolectric.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
public class FileEncryptionPreferenceControllerTest {
@Mock
private Preference mPreference;
@Mock
private PreferenceScreen mPreferenceScreen;
@Mock
private IStorageManager mStorageManager;
private Context mContext;
private FileEncryptionPreferenceController mController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mController = new FileEncryptionPreferenceController(mContext);
when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
.thenReturn(mPreference);
}
@Test
public void isAvailable_storageManagerNull_shouldBeFalse() {
ReflectionHelpers.setField(mController, "mStorageManager", null);
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_notConvertibleToFBE_shouldBeFalse() throws RemoteException {
ReflectionHelpers.setField(mController, "mStorageManager", mStorageManager);
when(mStorageManager.isConvertibleToFBE()).thenReturn(false);
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_convertibleToFBE_shouldBeTrue() throws RemoteException {
ReflectionHelpers.setField(mController, "mStorageManager", mStorageManager);
when(mStorageManager.isConvertibleToFBE()).thenReturn(true);
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void updateState_settingIsNotFile_shouldDoNothing() throws RemoteException {
ReflectionHelpers.setField(mController, "mStorageManager", mStorageManager);
when(mStorageManager.isConvertibleToFBE()).thenReturn(true);
mController.displayPreference(mPreferenceScreen);
CryptoProperties.type(CryptoProperties.type_values.NONE);
mController.updateState(mPreference);
verify(mPreference, never()).setEnabled(anyBoolean());
verify(mPreference, never()).setSummary(anyString());
}
@Test
public void updateState_settingIsFile_shouldSetSummaryAndDisablePreference()
throws RemoteException {
ReflectionHelpers.setField(mController, "mStorageManager", mStorageManager);
when(mStorageManager.isConvertibleToFBE()).thenReturn(true);
mController.displayPreference(mPreferenceScreen);
CryptoProperties.type(CryptoProperties.type_values.FILE);
mController.updateState(mPreference);
verify(mPreference).setEnabled(false);
verify(mPreference).setSummary(mContext.getString(R.string.convert_to_file_encryption_done));
}
}

View File

@@ -19,8 +19,11 @@ package com.android.settings.accessibility;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.content.Context; import android.content.Context;
import android.os.Looper;
import android.provider.Settings; import android.provider.Settings;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference; import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -37,6 +40,7 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class HighTextContrastPreferenceControllerTest { public class HighTextContrastPreferenceControllerTest {
private static final String PREF_KEY = "text_contrast";
private static final int ON = 1; private static final int ON = 1;
private static final int OFF = 0; private static final int OFF = 0;
private static final int UNKNOWN = -1; private static final int UNKNOWN = -1;
@@ -44,12 +48,20 @@ public class HighTextContrastPreferenceControllerTest {
private Context mContext; private Context mContext;
private SwitchPreference mPreference; private SwitchPreference mPreference;
private HighTextContrastPreferenceController mController; private HighTextContrastPreferenceController mController;
private PreferenceScreen mScreen;
@Before @Before
public void setUp() { public void setUp() {
mContext = ApplicationProvider.getApplicationContext(); mContext = ApplicationProvider.getApplicationContext();
if (Looper.myLooper() == null) {
Looper.prepare();
}
final PreferenceManager preferenceManager = new PreferenceManager(mContext);
mScreen = preferenceManager.createPreferenceScreen(mContext);
mPreference = new SwitchPreference(mContext); mPreference = new SwitchPreference(mContext);
mController = new HighTextContrastPreferenceController(mContext, "text_contrast"); mPreference.setKey(PREF_KEY);
mScreen.addPreference(mPreference);
mController = new HighTextContrastPreferenceController(mContext, PREF_KEY);
} }
@Test @Test
@@ -99,10 +111,13 @@ public class HighTextContrastPreferenceControllerTest {
@Test @Test
public void resetState_shouldDisableTextContrast() { public void resetState_shouldDisableTextContrast() {
mController.displayPreference(mScreen);
mController.setChecked(true); mController.setChecked(true);
mPreference.setChecked(true);
mController.resetState(); mController.resetState();
assertThat(mPreference.isChecked()).isFalse();
assertThat(Settings.Secure.getInt(mContext.getContentResolver(), assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, UNKNOWN)).isEqualTo(OFF); Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, UNKNOWN)).isEqualTo(OFF);
} }

View File

@@ -17,6 +17,7 @@
package com.android.settings.safetycenter; package com.android.settings.safetycenter;
import static android.safetycenter.SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES; import static android.safetycenter.SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES;
import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID;
import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCE_IDS; import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCE_IDS;
import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED; import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED;
import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED; import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED;
@@ -147,6 +148,29 @@ public class SafetySourceBroadcastReceiverTest {
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED).build()); new SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED).build());
} }
@Test
public void onReceive_onRefreshWithBroadcastId_setsRefreshEventWithBroadcastId() {
final String refreshBroadcastId = "REFRESH_BROADCAST_ID";
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
Intent intent =
new Intent()
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
.putExtra(
EXTRA_REFRESH_SAFETY_SOURCE_IDS,
new String[]{ LockScreenSafetySource.SAFETY_SOURCE_ID })
.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, refreshBroadcastId);
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
ArgumentCaptor<SafetyEvent> captor = ArgumentCaptor.forClass(SafetyEvent.class);
verify(mSafetyCenterManagerWrapper, times(1))
.setSafetySourceData(any(), any(), any(), captor.capture());
assertThat(captor.getValue().getRefreshBroadcastId()).isEqualTo(refreshBroadcastId);
assertThat(captor.getValue()).isEqualTo(
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
.setRefreshBroadcastId(refreshBroadcastId).build());
}
@Test @Test
public void onReceive_onRefresh_withLockscreenSourceId_setsLockscreenData() { public void onReceive_onRefresh_withLockscreenSourceId_setsLockscreenData() {
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);