Snap for 10120310 from 5f40973695 to udc-qpr1-release

Change-Id: Ia120731de3dc4f6c8a68d3c05e987d82b02105bb
This commit is contained in:
Android Build Coastguard Worker
2023-05-12 03:27:10 +00:00
40 changed files with 1124 additions and 479 deletions

View File

@@ -1581,6 +1581,22 @@
column="5"/> column="5"/>
</issue> </issue>
<issue
id="HardCodedColor"
severity="Error"
message="Avoid using hardcoded color"
category="Correctness"
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;color name=&quot;switch_bar_state_disabled_color&quot;>#1FE3E3E3&lt;/color>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values-night/colors.xml"
line="76"
column="5"/>
</issue>
<issue <issue
id="HardCodedColor" id="HardCodedColor"
severity="Error" severity="Error"
@@ -2957,6 +2973,22 @@
column="5"/> column="5"/>
</issue> </issue>
<issue
id="HardCodedColor"
severity="Error"
message="Avoid using hardcoded color"
category="Correctness"
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;color name=&quot;switch_bar_state_disabled_color&quot;>#1F1F1F1F&lt;/color>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/values/colors.xml"
line="219"
column="5"/>
</issue>
<issue <issue
id="HardCodedColor" id="HardCodedColor"
severity="Error" severity="Error"
@@ -6253,6 +6285,38 @@
column="63"/> column="63"/>
</issue> </issue>
<issue
id="HardCodedColor"
severity="Error"
message="Avoid using hardcoded color"
category="Correctness"
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;solid android:color=&quot;@color/switch_bar_state_disabled_color&quot;/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/drawable/switch_bar_bg_disabled.xml"
line="22"
column="20"/>
</issue>
<issue
id="HardCodedColor"
severity="Error"
message="Avoid using hardcoded color"
category="Correctness"
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.&#xA;This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" &lt;solid android:color=&quot;@color/switch_bar_state_disabled_color&quot;/>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="res/drawable/switch_bar_bg_disabled.xml"
line="22"
column="20"/>
</issue>
<issue <issue
id="HardCodedColor" id="HardCodedColor"
severity="Error" severity="Error"

View File

@@ -19,6 +19,7 @@ message BatteryOptimizeHistoricalLogEntry {
APPLY = 2; APPLY = 2;
RESET = 3; RESET = 3;
RESTORE = 4; RESTORE = 4;
BACKUP = 5;
} }
optional string package_name = 1; optional string package_name = 1;

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 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.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/switch_bar_state_disabled_color"/>
<corners android:radius="@dimen/settingslib_switch_bar_radius"/>
</shape>
</item>
</ripple>

View File

@@ -96,4 +96,6 @@
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
<include layout="@layout/udfps_enroll_view" />
</com.google.android.setupdesign.GlifLayout> </com.google.android.setupdesign.GlifLayout>

View File

@@ -24,6 +24,7 @@
android:background="@android:color/transparent"> android:background="@android:color/transparent">
<FrameLayout <FrameLayout
android:id="@+id/frame"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:paddingStart="@dimen/settingslib_switchbar_padding_left" android:paddingStart="@dimen/settingslib_switchbar_padding_left"

View File

@@ -18,6 +18,7 @@
<com.google.android.setupdesign.GlifLayout <com.google.android.setupdesign.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/setup_wizard_layout" android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -41,10 +42,11 @@
<FrameLayout <FrameLayout
android:id="@+id/layout_container" android:id="@+id/layout_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="0dp"
android:clipChildren="false" android:clipChildren="false"
android:clipToPadding="false" android:clipToPadding="false"
android:layout_gravity="center_horizontal|bottom"> android:layout_gravity="center_horizontal|bottom"
tools:ignore="Suspicious0dp">
<!-- Animation res MUST be set in code --> <!-- Animation res MUST be set in code -->
<com.airbnb.lottie.LottieAnimationView <com.airbnb.lottie.LottieAnimationView
@@ -59,6 +61,9 @@
android:clipChildren="false" android:clipChildren="false"
android:clipToPadding="false" android:clipToPadding="false"
app:lottie_speed=".85" /> app:lottie_speed=".85" />
<include layout="@layout/udfps_enroll_view" />
</FrameLayout> </FrameLayout>
<TextView <TextView

View File

@@ -71,5 +71,8 @@
<!-- Flash notifications colors --> <!-- Flash notifications colors -->
<!-- Screen flash notification color selected stroke in color selection dialog --> <!-- Screen flash notification color selected stroke in color selection dialog -->
<color name="screen_flash_color_button_outer_circle_stroke_color">#FFFFFF</color> <color name="screen_flash_color_button_outer_circle_stroke_color">#FFFFFF</color>
<!-- Switch bar disabled state color-->
<color name="switch_bar_state_disabled_color">#1FE3E3E3</color>
</resources> </resources>

View File

@@ -214,4 +214,7 @@
<color name="screen_flash_preset_opacity_color_10">#4DFF017E</color> <!-- 30% Rose --> <color name="screen_flash_preset_opacity_color_10">#4DFF017E</color> <!-- 30% Rose -->
<color name="screen_flash_preset_opacity_color_11">#4DFF00FE</color> <!-- 30% Magenta --> <color name="screen_flash_preset_opacity_color_11">#4DFF00FE</color> <!-- 30% Magenta -->
<color name="screen_flash_preset_opacity_color_12">#667F00FF</color> <!-- 40% Violet --> <color name="screen_flash_preset_opacity_color_12">#667F00FF</color> <!-- 40% Violet -->
<!-- Switch bar disabled state color-->
<color name="switch_bar_state_disabled_color">#1F1F1F1F</color>
</resources> </resources>

View File

@@ -119,9 +119,9 @@
<!-- Connected devices settings. Title of the dialog to hint user to pair other ear of the hearing aid device. Shows when only one of the hearing aid device set is connected. [CHAR LIMIT=25] --> <!-- Connected devices settings. Title of the dialog to hint user to pair other ear of the hearing aid device. Shows when only one of the hearing aid device set is connected. [CHAR LIMIT=25] -->
<string name="bluetooth_pair_other_ear_dialog_title">Pair your other ear</string> <string name="bluetooth_pair_other_ear_dialog_title">Pair your other ear</string>
<!-- Connected devices settings. Message of the dialog to hint user to pair right ear of the hearing aid device. Shows when only left side of hearing aid device set is connected. [CHAR LIMIT=NONE] --> <!-- Connected devices settings. Message of the dialog to hint user to pair right ear of the hearing aid device. Shows when only left side of hearing aid device set is connected. [CHAR LIMIT=NONE] -->
<string name="bluetooth_pair_other_ear_dialog_left_ear_message">Your left hearing aid is connected.\n\nTo pair the right one, make sure it\u2019s turned on and ready to pair.</string> <string name="bluetooth_pair_other_ear_dialog_left_ear_message">Your left hearing device is connected.\n\nTo pair the right one, make sure it\u2019s turned on and ready to pair.</string>
<!-- Connected devices settings. Message of the dialog to hint user to pair other ear of the hearing aid device. Shows when only right side of the hearing aid device set is connected. [CHAR LIMIT=NONE] --> <!-- Connected devices settings. Message of the dialog to hint user to pair other ear of the hearing aid device. Shows when only right side of the hearing aid device set is connected. [CHAR LIMIT=NONE] -->
<string name="bluetooth_pair_other_ear_dialog_right_ear_message">Your right hearing aid is connected.\n\nTo pair the left one, make sure it\u2019s turned on and ready to pair.</string> <string name="bluetooth_pair_other_ear_dialog_right_ear_message">Your right hearing device is connected.\n\nTo pair the left one, make sure it\u2019s turned on and ready to pair.</string>
<!-- Connected devices settings. Positive button of the dialog to help user to pair right ear of the hearing aid device. Dialog shows when only one of the hearing aid device set is connected. [CHAR LIMIT=20] --> <!-- Connected devices settings. Positive button of the dialog to help user to pair right ear of the hearing aid device. Dialog shows when only one of the hearing aid device set is connected. [CHAR LIMIT=20] -->
<string name="bluetooth_pair_other_ear_dialog_right_ear_positive_button">Pair right ear</string> <string name="bluetooth_pair_other_ear_dialog_right_ear_positive_button">Pair right ear</string>
<!-- Connected devices settings. Positive button of the dialog to help user to pair left ear of the hearing aid device. Dialog shows when only one of the hearing aid device set is connected. [CHAR LIMIT=20] --> <!-- Connected devices settings. Positive button of the dialog to help user to pair left ear of the hearing aid device. Dialog shows when only one of the hearing aid device set is connected. [CHAR LIMIT=20] -->
@@ -1182,20 +1182,20 @@
<string name="current_screen_lock">Current screen lock</string> <string name="current_screen_lock">Current screen lock</string>
<!-- Title for preference that guides the user through creating a backup unlock pattern for fingerprint [CHAR LIMIT=45]--> <!-- Title for preference that guides the user through creating a backup unlock pattern for fingerprint [CHAR LIMIT=45]-->
<string name="fingerprint_unlock_set_unlock_pattern">Fingerprint + Pattern</string> <string name="fingerprint_unlock_set_unlock_pattern">Pattern \u2022 Fingerprint</string>
<!-- Title for preference that guides the user through creating a backup unlock PIN for fingerprint [CHAR LIMIT=45]--> <!-- Title for preference that guides the user through creating a backup unlock PIN for fingerprint [CHAR LIMIT=45]-->
<string name="fingerprint_unlock_set_unlock_pin">Fingerprint + PIN</string> <string name="fingerprint_unlock_set_unlock_pin">PIN \u2022 Fingerprint</string>
<!-- Title for preference that guides the user through creating a backup unlock password for fingerprint [CHAR LIMIT=45]--> <!-- Title for preference that guides the user through creating a backup unlock password for fingerprint [CHAR LIMIT=45]-->
<string name="fingerprint_unlock_set_unlock_password">Fingerprint + Password</string> <string name="fingerprint_unlock_set_unlock_password">Password \u2022 Fingerprint</string>
<!-- Title for preference that guides the user to skip fingerprint setup [CHAR LIMIT=60]--> <!-- Title for preference that guides the user to skip fingerprint setup [CHAR LIMIT=60]-->
<string name="fingerprint_unlock_skip_fingerprint">Continue without fingerprint</string> <string name="fingerprint_unlock_skip_fingerprint">Continue without fingerprint</string>
<!-- Title for preference that guides the user through creating a backup unlock pattern for Face Unlock [CHAR LIMIT=45]--> <!-- Title for preference that guides the user through creating a backup unlock pattern for Face Unlock [CHAR LIMIT=45]-->
<string name="face_unlock_set_unlock_pattern">Face Unlock + Pattern</string> <string name="face_unlock_set_unlock_pattern">Pattern \u2022 Face</string>
<!-- Title for preference that guides the user through creating a backup unlock PIN for Face Unlock [CHAR LIMIT=45]--> <!-- Title for preference that guides the user through creating a backup unlock PIN for Face Unlock [CHAR LIMIT=45]-->
<string name="face_unlock_set_unlock_pin">Face Unlock + PIN</string> <string name="face_unlock_set_unlock_pin">PIN \u2022 Face</string>
<!-- Title for preference that guides the user through creating a backup unlock password for Face Unlock [CHAR LIMIT=45]--> <!-- Title for preference that guides the user through creating a backup unlock password for Face Unlock [CHAR LIMIT=45]-->
<string name="face_unlock_set_unlock_password">Face Unlock + Password</string> <string name="face_unlock_set_unlock_password">Password \u2022 Face</string>
<!-- Title for preference that guides the user to skip Face Unlock setup [CHAR LIMIT=60]--> <!-- Title for preference that guides the user to skip Face Unlock setup [CHAR LIMIT=60]-->
<string name="face_unlock_skip_face">Continue without Face Unlock</string> <string name="face_unlock_skip_face">Continue without Face Unlock</string>
@@ -1505,6 +1505,8 @@
<string name="bluetooth_companion_app_remove_association_dialog_title">Disconnect App?</string> <string name="bluetooth_companion_app_remove_association_dialog_title">Disconnect App?</string>
<!-- Bluetooth device details companion apps. The body of confirmation dialog for remove association. [CHAR LIMIT=60] --> <!-- Bluetooth device details companion apps. The body of confirmation dialog for remove association. [CHAR LIMIT=60] -->
<string name="bluetooth_companion_app_body"><xliff:g id="app_name" example="App Name">%1$s</xliff:g> app will no longer connect to your <xliff:g id="device_name" example="Device Name">%2$s</xliff:g></string> <string name="bluetooth_companion_app_body"><xliff:g id="app_name" example="App Name">%1$s</xliff:g> app will no longer connect to your <xliff:g id="device_name" example="Device Name">%2$s</xliff:g></string>
<!-- Summary of Bluetooth LE Audio toggle in Device Details. [CHAR LIMIT=40] -->
<string name="device_details_leaudio_toggle_summary">Experimental. Improves audio quality.</string>
<!-- Bluetooth device details. In the confirmation dialog for unpairing a paired device, this is the label on the button that will complete the unpairing action. --> <!-- Bluetooth device details. In the confirmation dialog for unpairing a paired device, this is the label on the button that will complete the unpairing action. -->
<string name="bluetooth_unpair_dialog_forget_confirm_button">Forget device</string> <string name="bluetooth_unpair_dialog_forget_confirm_button">Forget device</string>
@@ -4670,7 +4672,7 @@
<!-- Introduction for the Hearing devices page to introduce feature. [CHAR LIMIT=NONE] --> <!-- Introduction for the Hearing devices page to introduce feature. [CHAR LIMIT=NONE] -->
<string name="accessibility_hearingaid_intro">You can use hearing aids, cochlear implants, and other amplification devices with your phone</string> <string name="accessibility_hearingaid_intro">You can use hearing aids, cochlear implants, and other amplification devices with your phone</string>
<!-- Summary for the accessibility preference for hearing aid when not connected. [CHAR LIMIT=50] --> <!-- Summary for the accessibility preference for hearing aid when not connected. [CHAR LIMIT=50] -->
<string name="accessibility_hearingaid_not_connected_summary">No hearing aids connected</string> <string name="accessibility_hearingaid_not_connected_summary">No hearing devices connected</string>
<!-- Summary for the accessibility preference for hearing aid when adding new devices. [CHAR LIMIT=50] --> <!-- Summary for the accessibility preference for hearing aid when adding new devices. [CHAR LIMIT=50] -->
<string name="accessibility_hearingaid_adding_summary">Add hearing aids</string> <string name="accessibility_hearingaid_adding_summary">Add hearing aids</string>
<!-- Title of the pair instruction dialog. Dialog shows to ask the user to make sure that their hearing aid devices are in pairing mode. [CHAR LIMIT=25] --> <!-- Title of the pair instruction dialog. Dialog shows to ask the user to make sure that their hearing aid devices are in pairing mode. [CHAR LIMIT=25] -->
@@ -10306,7 +10308,16 @@
<string name="credman_confirmation_message_title">Turn off %1$s\?</string> <string name="credman_confirmation_message_title">Turn off %1$s\?</string>
<!-- Message of the warning dialog for disabling the credential provider. [CHAR_LIMIT=NONE] --> <!-- Message of the warning dialog for disabling the credential provider. [CHAR_LIMIT=NONE] -->
<string name="credman_confirmation_message">Saved info like addresses or payment methods won\'t be filled in when you sign in. To keep your saved info filled in, set enable a password, passkey and data/or service.</string> <string name="credman_confirmation_message">
<![CDATA[
<b>Turn off this service?</b>
<br/>
<br/>
Saved info like passwords, passkeys, payment methods, and other info won\'t be filled
in when you sign in. To use your saved info, choose a password, passkey, or data
service.
]]>
</string>
<!-- Title of the warning dialog for enabling the credential provider. [CHAR_LIMIT=NONE] --> <!-- Title of the warning dialog for enabling the credential provider. [CHAR_LIMIT=NONE] -->
<string name="credman_enable_confirmation_message_title">Use %1$s\?</string> <string name="credman_enable_confirmation_message_title">Use %1$s\?</string>

View File

@@ -17,16 +17,26 @@
package com.android.settings.accessibility; package com.android.settings.accessibility;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R; import com.android.settings.R;
import com.android.settingslib.Utils;
/** /**
* Preference for Flash notifications preview. * Preference for Flash notifications preview.
*/ */
public class FlashNotificationsPreviewPreference extends Preference { public class FlashNotificationsPreviewPreference extends Preference {
private Drawable mBackgroundEnabled;
private Drawable mBackgroundDisabled;
@ColorInt
private int mTextColorDisabled;
public FlashNotificationsPreviewPreference(Context context) { public FlashNotificationsPreviewPreference(Context context) {
super(context); super(context);
@@ -52,5 +62,32 @@ public class FlashNotificationsPreviewPreference extends Preference {
private void init() { private void init() {
setLayoutResource(R.layout.flash_notification_preview_preference); setLayoutResource(R.layout.flash_notification_preview_preference);
mBackgroundEnabled = getContext().getDrawable(R.drawable.settingslib_switch_bar_bg_on);
mBackgroundDisabled = getContext().getDrawable(R.drawable.switch_bar_bg_disabled);
mTextColorDisabled = Utils.getColorAttrDefaultColor(getContext(),
android.R.attr.textColorPrimary);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
final boolean enabled = isEnabled();
final View frame = holder.findViewById(R.id.frame);
if (frame != null) {
frame.setBackground(enabled ? mBackgroundEnabled : mBackgroundDisabled);
}
final TextView title = (TextView) holder.findViewById(android.R.id.title);
if (title != null) {
@ColorInt final int textColorEnabled = title.getCurrentTextColor();
title.setAlpha(enabled ? 1f : 0.38f);
title.setTextColor(enabled ? textColorEnabled : mTextColorDisabled);
}
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
notifyChanged();
} }
} }

View File

@@ -55,7 +55,7 @@ public class FlashNotificationsPreviewPreferenceController extends
new Handler(Looper.getMainLooper())) { new Handler(Looper.getMainLooper())) {
@Override @Override
public void onChange(boolean selfChange, @Nullable Uri uri) { public void onChange(boolean selfChange, @Nullable Uri uri) {
onSettingChanged(); updateState(mPreference);
} }
}; };
@@ -73,7 +73,7 @@ public class FlashNotificationsPreviewPreferenceController extends
public void displayPreference(PreferenceScreen screen) { public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen); super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey()); mPreference = screen.findPreference(getPreferenceKey());
onSettingChanged(); updateState(mPreference);
} }
@Override @Override
@@ -103,10 +103,13 @@ public class FlashNotificationsPreviewPreferenceController extends
} }
} }
private void onSettingChanged() { @Override
if (mPreference == null) return; public void updateState(Preference preference) {
super.updateState(preference);
mPreference.setEnabled(FlashNotificationsUtil.getFlashNotificationsState(mContext) if (preference == null) {
return;
}
preference.setEnabled(FlashNotificationsUtil.getFlashNotificationsState(mContext)
!= FlashNotificationsUtil.State.OFF); != FlashNotificationsUtil.State.OFF);
} }
} }

View File

@@ -553,21 +553,9 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
mPrefs.get(packageName).setChecked(true); mPrefs.get(packageName).setChecked(true);
} }
return true; return true;
} else {
// If we are disabling the last enabled provider then show a warning.
if (mEnabledPackageNames.size() <= 1) {
final DialogFragment fragment =
newConfirmationDialogFragment(packageName, title, pref);
if (fragment == null || mFragmentManager == null) {
return true;
}
fragment.show(mFragmentManager, ConfirmationDialogFragment.TAG);
} else { } else {
togglePackageNameDisabled(packageName); togglePackageNameDisabled(packageName);
} }
}
return true; return true;
}); });
@@ -682,35 +670,6 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
return new ErrorDialogFragment(host); return new ErrorDialogFragment(host);
} }
private @Nullable ConfirmationDialogFragment newConfirmationDialogFragment(
@NonNull String packageName,
@NonNull CharSequence appName,
@NonNull SwitchPreference pref) {
DialogHost host =
new DialogHost() {
@Override
public void onDialogClick(int whichButton) {
if (whichButton == DialogInterface.BUTTON_POSITIVE) {
// Since the package is now enabled then we
// should remove it from the enabled list.
togglePackageNameDisabled(packageName);
} else if (whichButton == DialogInterface.BUTTON_NEGATIVE) {
// Set the checked back to true because we
// backed out of turning this off.
pref.setChecked(true);
}
}
@Override
public void onCancel() {
// If we dismiss the dialog then re-enable.
pref.setChecked(true);
}
};
return new ConfirmationDialogFragment(host, packageName, appName);
}
protected int getUser() { protected int getUser() {
if (mIsWorkProfile) { if (mIsWorkProfile) {
UserHandle workProfile = Utils.getManagedProfile(UserManager.get(mContext)); UserHandle workProfile = Utils.getManagedProfile(UserManager.get(mContext));
@@ -800,46 +759,6 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl
public void onClick(DialogInterface dialog, int which) {} public void onClick(DialogInterface dialog, int which) {}
} }
/**
* Confirmation dialog fragment shows a dialog to the user to confirm that they are disabling a
* provider.
*/
public static class ConfirmationDialogFragment extends CredentialManagerDialogFragment {
ConfirmationDialogFragment(
DialogHost dialogHost, @NonNull String packageName, @NonNull CharSequence appName) {
super(dialogHost);
final Bundle argument = new Bundle();
argument.putString(PACKAGE_NAME_KEY, packageName);
argument.putCharSequence(APP_NAME_KEY, appName);
setArguments(argument);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Bundle bundle = getArguments();
final String title =
getContext()
.getString(
R.string.credman_confirmation_message_title,
bundle.getCharSequence(
CredentialManagerDialogFragment.APP_NAME_KEY));
return new AlertDialog.Builder(getActivity())
.setTitle(title)
.setMessage(getContext().getString(R.string.credman_confirmation_message))
.setPositiveButton(R.string.credman_confirmation_message_positive_button, this)
.setNegativeButton(android.R.string.cancel, this)
.create();
}
@Override
public void onClick(DialogInterface dialog, int which) {
getDialogHost().onDialogClick(which);
}
}
/** /**
* Confirmation dialog fragment shows a dialog to the user to confirm that they would like to * Confirmation dialog fragment shows a dialog to the user to confirm that they would like to
* enable the new provider. * enable the new provider.

View File

@@ -273,8 +273,13 @@ public class DefaultCombinedPicker extends DefaultAppPickerFragment {
@Override @Override
protected CharSequence getConfirmationMessage(CandidateInfo appInfo) { protected CharSequence getConfirmationMessage(CandidateInfo appInfo) {
// If we are selecting none then show a warning label.
if (appInfo == null) { if (appInfo == null) {
return null; final String message =
getContext()
.getString(
R.string.credman_confirmation_message);
return Html.fromHtml(message);
} }
final CharSequence appName = appInfo.loadLabel(); final CharSequence appName = appInfo.loadLabel();
final String message = final String message =

View File

@@ -261,6 +261,8 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
int rotation = getApplicationContext().getDisplay().getRotation(); int rotation = getApplicationContext().getDisplay().getRotation();
final GlifLayout layout = (GlifLayout) getLayoutInflater().inflate( final GlifLayout layout = (GlifLayout) getLayoutInflater().inflate(
R.layout.udfps_enroll_enrolling, null, false); R.layout.udfps_enroll_enrolling, null, false);
final UdfpsEnrollView udfpsEnrollView = layout.findViewById(R.id.udfps_animation_view);
updateUdfpsEnrollView(udfpsEnrollView, props.get(0));
switch (rotation) { switch (rotation) {
case Surface.ROTATION_90: case Surface.ROTATION_90:
final View sudContent = layout.findViewById(R.id.sud_layout_content); final View sudContent = layout.findViewById(R.id.sud_layout_content);
@@ -282,33 +284,17 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
? 0 : (int) getResources().getDimension( ? 0 : (int) getResources().getDimension(
R.dimen.rotation_90_enroll_padding_end), 0); R.dimen.rotation_90_enroll_padding_end), 0);
layoutContainer.setLayoutParams(lp); layoutContainer.setLayoutParams(lp);
if (FeatureFlagUtils.isEnabled(getApplicationContext(),
FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) {
final UdfpsEnrollView udfpsEnrollView = addUdfpsEnrollView(props.get(0));
layout.addView(udfpsEnrollView);
setOnHoverListener(true, layout, udfpsEnrollView); setOnHoverListener(true, layout, udfpsEnrollView);
}
setContentView(layout, lp); setContentView(layout, lp);
break; break;
case Surface.ROTATION_0: case Surface.ROTATION_0:
case Surface.ROTATION_180: case Surface.ROTATION_180:
if (FeatureFlagUtils.isEnabled(getApplicationContext(), // In the portrait mode, layout_container's height is 0, so it's
FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) {
final UdfpsEnrollView udfpsEnrollView = addUdfpsEnrollView(props.get(0));
// In the portrait mode, set layout_container's height 0, so it's
// always shown at the bottom of the screen. // always shown at the bottom of the screen.
// Add udfps enroll view into layout_container instead of
// udfps_enroll_enrolling, so that when the content is too long to
// make udfps_enroll_enrolling larger than the screen, udfps enroll
// view could still be set to right position by setting bottom margin to
// its parent view (layout_container) because it's always at the
// bottom of the screen.
final FrameLayout portraitLayoutContainer = layout.findViewById( final FrameLayout portraitLayoutContainer = layout.findViewById(
R.id.layout_container); R.id.layout_container);
final ViewGroup.LayoutParams containerLp =
portraitLayoutContainer.getLayoutParams();
containerLp.height = 0;
// In the portrait mode, the title and lottie animation view may // In the portrait mode, the title and lottie animation view may
// overlap when title needs three lines, so adding some paddings // overlap when title needs three lines, so adding some paddings
@@ -326,22 +312,24 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
fingerprintView.setPadding(0, -layoutLottieAnimationPadding, fingerprintView.setPadding(0, -layoutLottieAnimationPadding,
0, layoutLottieAnimationPadding); 0, layoutLottieAnimationPadding);
portraitLayoutContainer.addView(udfpsEnrollView); // TODO(b/260970216) Instead of hiding the description text view, we should
setOnHoverListener(false, layout, udfpsEnrollView); // make the header view scrollable if the text is too long.
// If description text view has overlap with udfps progress view, hide it.
View view = layout.getDescriptionTextView();
layout.getViewTreeObserver().addOnDrawListener(() -> {
if (view.getVisibility() == View.VISIBLE
&& hasOverlap(view, udfpsEnrollView)) {
view.setVisibility(View.GONE);
} }
});
setOnHoverListener(false, layout, udfpsEnrollView);
setContentView(layout); setContentView(layout);
break; break;
case Surface.ROTATION_270: case Surface.ROTATION_270:
default: default:
if (FeatureFlagUtils.isEnabled(getApplicationContext(),
FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) {
final UdfpsEnrollView udfpsEnrollView = addUdfpsEnrollView(props.get(0));
layout.addView(udfpsEnrollView);
setOnHoverListener(true, layout, udfpsEnrollView); setOnHoverListener(true, layout, udfpsEnrollView);
}
setContentView(layout); setContentView(layout);
break; break;
} }
@@ -1241,10 +1229,8 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
} }
} }
private UdfpsEnrollView addUdfpsEnrollView(FingerprintSensorPropertiesInternal udfpsProps) { private UdfpsEnrollView updateUdfpsEnrollView(UdfpsEnrollView udfpsEnrollView,
UdfpsEnrollView udfpsEnrollView = (UdfpsEnrollView) getLayoutInflater().inflate( FingerprintSensorPropertiesInternal udfpsProps) {
R.layout.udfps_enroll_view, null, false);
DisplayInfo displayInfo = new DisplayInfo(); DisplayInfo displayInfo = new DisplayInfo();
getDisplay().getDisplayInfo(displayInfo); getDisplay().getDisplayInfo(displayInfo);
mScaleFactor = mUdfpsUtils.getScaleFactor(displayInfo); mScaleFactor = mUdfpsUtils.getScaleFactor(displayInfo);
@@ -1311,6 +1297,24 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
: R.id.sud_layout_content).setOnHoverListener(onHoverListener); : R.id.sud_layout_content).setOnHoverListener(onHoverListener);
} }
@VisibleForTesting boolean hasOverlap(View view1, View view2) {
int[] firstPosition = new int[2];
int[] secondPosition = new int[2];
view1.getLocationOnScreen(firstPosition);
view2.getLocationOnScreen(secondPosition);
// Rect constructor parameters: left, top, right, bottom
Rect rectView1 = new Rect(firstPosition[0], firstPosition[1],
firstPosition[0] + view1.getMeasuredWidth(),
firstPosition[1] + view1.getMeasuredHeight());
Rect rectView2 = new Rect(secondPosition[0], secondPosition[1],
secondPosition[0] + view2.getMeasuredWidth(),
secondPosition[1] + view2.getMeasuredHeight());
return rectView1.intersect(rectView2);
}
public static class IconTouchDialog extends InstrumentedDialogFragment { public static class IconTouchDialog extends InstrumentedDialogFragment {
@Override @Override

View File

@@ -185,7 +185,8 @@ public class FingerprintSettings extends SubSettings {
private static final int MSG_FINGER_AUTH_HELP = 1004; private static final int MSG_FINGER_AUTH_HELP = 1004;
private static final int CONFIRM_REQUEST = 101; private static final int CONFIRM_REQUEST = 101;
private static final int CHOOSE_LOCK_GENERIC_REQUEST = 102; @VisibleForTesting
static final int CHOOSE_LOCK_GENERIC_REQUEST = 102;
@VisibleForTesting @VisibleForTesting
static final int ADD_FINGERPRINT_REQUEST = 10; static final int ADD_FINGERPRINT_REQUEST = 10;
private static final int AUTO_ADD_FIRST_FINGERPRINT_REQUEST = 11; private static final int AUTO_ADD_FIRST_FINGERPRINT_REQUEST = 11;
@@ -1014,7 +1015,7 @@ public class FingerprintSettings extends SubSettings {
true); true);
intent.putExtra(Intent.EXTRA_USER_ID, mUserId); intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
intent.putExtra(Intent.EXTRA_USER_ID, mUserId); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true);
startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST); startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST);
} }
} }

View File

@@ -161,7 +161,6 @@ public class UdfpsEnrollView extends FrameLayout implements UdfpsEnrollHelper.Li
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) getLayoutParams(); MarginLayoutParams marginLayoutParams = (MarginLayoutParams) getLayoutParams();
FrameLayout.LayoutParams params = (LayoutParams) getLayoutParams(); FrameLayout.LayoutParams params = (LayoutParams) getLayoutParams();
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) { if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
parentView.getViewTreeObserver().addOnDrawListener(() -> {
final int[] coords = parentView.getLocationOnScreen(); final int[] coords = parentView.getLocationOnScreen();
final int parentLeft = coords[0]; final int parentLeft = coords[0];
final int parentTop = coords[1]; final int parentTop = coords[1];
@@ -176,7 +175,6 @@ public class UdfpsEnrollView extends FrameLayout implements UdfpsEnrollHelper.Li
marginLayoutParams.rightMargin = rightMargin; marginLayoutParams.rightMargin = rightMargin;
marginLayoutParams.topMargin = topMargin; marginLayoutParams.topMargin = topMargin;
setLayoutParams(params); setLayoutParams(params);
});
} else { } else {
final int[] coords = parentView.getLocationOnScreen(); final int[] coords = parentView.getLocationOnScreen();
final int parentLeft = coords[0]; final int parentLeft = coords[0];

View File

@@ -57,7 +57,9 @@ import com.android.settingslib.widget.LayoutPreference;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
@@ -92,13 +94,12 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
@VisibleForTesting @VisibleForTesting
final Map<String, Bitmap> mIconCache; final Map<String, Bitmap> mIconCache;
private CachedBluetoothDevice mCachedDevice; private CachedBluetoothDevice mCachedDevice;
private Set<BluetoothDevice> mBluetoothDevices;
@VisibleForTesting @VisibleForTesting
BluetoothAdapter mBluetoothAdapter; BluetoothAdapter mBluetoothAdapter;
@VisibleForTesting @VisibleForTesting
Handler mHandler = new Handler(Looper.getMainLooper()); Handler mHandler = new Handler(Looper.getMainLooper());
@VisibleForTesting @VisibleForTesting
boolean mIsRegisterCallback = false;
@VisibleForTesting
boolean mIsLeftDeviceEstimateReady; boolean mIsLeftDeviceEstimateReady;
@VisibleForTesting @VisibleForTesting
boolean mIsRightDeviceEstimateReady; boolean mIsRightDeviceEstimateReady;
@@ -141,23 +142,13 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
if (!isAvailable()) { if (!isAvailable()) {
return; return;
} }
mIsRegisterCallback = true; registerBluetoothDevice();
mCachedDevice.registerCallback(this);
mBluetoothAdapter.addOnMetadataChangedListener(mCachedDevice.getDevice(),
mContext.getMainExecutor(), mMetadataListener);
refresh(); refresh();
} }
@Override @Override
public void onStop() { public void onStop() {
if (!mIsRegisterCallback) { unRegisterBluetoothDevice();
return;
}
mCachedDevice.unregisterCallback(this);
mBluetoothAdapter.removeOnMetadataChangedListener(mCachedDevice.getDevice(),
mMetadataListener);
mIsRegisterCallback = false;
} }
@Override @Override
@@ -175,6 +166,40 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
mCachedDevice = cachedBluetoothDevice; mCachedDevice = cachedBluetoothDevice;
} }
private void registerBluetoothDevice() {
if (mBluetoothDevices == null) {
mBluetoothDevices = new HashSet<>();
}
mBluetoothDevices.clear();
if (mCachedDevice.getDevice() != null) {
mBluetoothDevices.add(mCachedDevice.getDevice());
}
mCachedDevice.getMemberDevice().forEach(cbd -> {
if (cbd != null) {
mBluetoothDevices.add(cbd.getDevice());
}
});
if (mBluetoothDevices.isEmpty()) {
Log.d(TAG, "No BT devcie to register.");
return;
}
mCachedDevice.registerCallback(this);
mBluetoothDevices.forEach(bd ->
mBluetoothAdapter.addOnMetadataChangedListener(bd,
mContext.getMainExecutor(), mMetadataListener));
}
private void unRegisterBluetoothDevice() {
if (mBluetoothDevices == null || mBluetoothDevices.isEmpty()) {
Log.d(TAG, "No BT devcie to unregister.");
return;
}
mCachedDevice.unregisterCallback(this);
mBluetoothDevices.forEach(bd -> mBluetoothAdapter.removeOnMetadataChangedListener(bd,
mMetadataListener));
mBluetoothDevices.clear();
}
@VisibleForTesting @VisibleForTesting
void refresh() { void refresh() {
if (mLayoutPreference != null && mCachedDevice != null) { if (mLayoutPreference != null && mCachedDevice != null) {

View File

@@ -120,6 +120,10 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
pref.setTitle(profile.getNameResource(mCachedDevice.getDevice())); pref.setTitle(profile.getNameResource(mCachedDevice.getDevice()));
pref.setOnPreferenceClickListener(this); pref.setOnPreferenceClickListener(this);
pref.setOrder(profile.getOrdinal()); pref.setOrder(profile.getOrdinal());
if (profile instanceof LeAudioProfile) {
pref.setSummary(R.string.device_details_leaudio_toggle_summary);
}
return pref; return pref;
} }

View File

@@ -196,10 +196,11 @@ public abstract class DeviceListPreferenceFragment extends
} }
// Prevent updates while the list shows one of the state messages // Prevent updates while the list shows one of the state messages
if (mBluetoothAdapter.getState() != BluetoothAdapter.STATE_ON) return; if (mBluetoothAdapter.getState() != BluetoothAdapter.STATE_ON) {
return;
}
if (mLeScanFilters != null if (mFilter != null && mFilter.matches(cachedDevice.getDevice())) {
|| (mFilter != null && mFilter.matches(cachedDevice.getDevice()))) {
createDevicePreference(cachedDevice); createDevicePreference(cachedDevice);
} }
} }
@@ -325,7 +326,12 @@ public abstract class DeviceListPreferenceFragment extends
if (cachedDevice == null) { if (cachedDevice == null) {
cachedDevice = mCachedDeviceManager.addDevice(device); cachedDevice = mCachedDeviceManager.addDevice(device);
} }
onDeviceAdded(cachedDevice); // Only add device preference when it's not found in the map and there's no other
// state message showing in the list
if (mDevicePreferenceMap.get(cachedDevice) == null
&& mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
createDevicePreference(cachedDevice);
}
} }
@Override @Override

View File

@@ -48,6 +48,8 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
private final DevelopmentSettingsDashboardFragment mFragment; private final DevelopmentSettingsDashboardFragment mFragment;
private final GraphicsDriverSystemPropertiesWrapper mSystemProperties;
@VisibleForTesting @VisibleForTesting
static final String PROPERTY_RO_GFX_ANGLE_SUPPORTED = "ro.gfx.angle.supported"; static final String PROPERTY_RO_GFX_ANGLE_SUPPORTED = "ro.gfx.angle.supported";
@@ -57,11 +59,34 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
@VisibleForTesting @VisibleForTesting
static final String ANGLE_DRIVER_SUFFIX = "angle"; static final String ANGLE_DRIVER_SUFFIX = "angle";
@VisibleForTesting
static class Injector {
public GraphicsDriverSystemPropertiesWrapper createSystemPropertiesWrapper() {
return new GraphicsDriverSystemPropertiesWrapper() {
@Override
public String get(String key, String def) {
return SystemProperties.get(key, def);
}
@Override
public void set(String key, String val) {
SystemProperties.set(key, val);
}
};
}
}
public GraphicsDriverEnableAngleAsSystemDriverController( public GraphicsDriverEnableAngleAsSystemDriverController(
Context context, DevelopmentSettingsDashboardFragment fragment) { Context context, DevelopmentSettingsDashboardFragment fragment) {
this(context, fragment, new Injector());
}
@VisibleForTesting
GraphicsDriverEnableAngleAsSystemDriverController(
Context context, DevelopmentSettingsDashboardFragment fragment, Injector injector) {
super(context); super(context);
mFragment = fragment; mFragment = fragment;
mSystemProperties = injector.createSystemPropertiesWrapper();
} }
@Override @Override
@@ -76,20 +101,27 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
// set "persist.graphics.egl" to "" if enableAngleAsSystemDriver is false // set "persist.graphics.egl" to "" if enableAngleAsSystemDriver is false
GraphicsEnvironment.getInstance().toggleAngleAsSystemDriver(enableAngleAsSystemDriver); GraphicsEnvironment.getInstance().toggleAngleAsSystemDriver(enableAngleAsSystemDriver);
// pop up a window asking user to reboot to make the new "persist.graphics.egl" take effect // pop up a window asking user to reboot to make the new "persist.graphics.egl" take effect
showRebootDialog();
return true;
}
@VisibleForTesting
void showRebootDialog() {
RebootConfirmationDialogFragment.show( RebootConfirmationDialogFragment.show(
mFragment, R.string.reboot_dialog_enable_angle_as_system_driver, mFragment, R.string.reboot_dialog_enable_angle_as_system_driver,
R.string.cancel, this); R.string.cancel, this);
return true;
} }
@Override @Override
public void updateState(Preference preference) { public void updateState(Preference preference) {
// set switch on if "persist.graphics.egl" is "angle" and angle is built in /vendor // set switch on if "persist.graphics.egl" is "angle" and angle is built in /vendor
// set switch off otherwise. // set switch off otherwise.
final String currentGlesDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL); final String currentGlesDriver =
mSystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
final boolean isAngle = TextUtils.equals(ANGLE_DRIVER_SUFFIX, currentGlesDriver); final boolean isAngle = TextUtils.equals(ANGLE_DRIVER_SUFFIX, currentGlesDriver);
final boolean isAngleSupported = final boolean isAngleSupported = TextUtils
TextUtils.equals(SystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED), "true"); .equals(mSystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED, ""), "true");
((SwitchPreference) mPreference).setChecked(isAngle && isAngleSupported); ((SwitchPreference) mPreference).setChecked(isAngle && isAngleSupported);
((SwitchPreference) mPreference).setEnabled(isAngleSupported); ((SwitchPreference) mPreference).setEnabled(isAngleSupported);
} }
@@ -98,8 +130,8 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
protected void onDeveloperOptionsSwitchEnabled() { protected void onDeveloperOptionsSwitchEnabled() {
// only enable the switch if ro.gfx.angle.supported is true // only enable the switch if ro.gfx.angle.supported is true
// we use ro.gfx.angle.supported to indicate if ANGLE libs are installed under /vendor // we use ro.gfx.angle.supported to indicate if ANGLE libs are installed under /vendor
final boolean isAngleSupported = final boolean isAngleSupported = TextUtils
TextUtils.equals(SystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED), "true"); .equals(mSystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED, ""), "true");
((SwitchPreference) mPreference).setEnabled(isAngleSupported); ((SwitchPreference) mPreference).setEnabled(isAngleSupported);
} }
@@ -116,7 +148,8 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
@Override @Override
public void onRebootCancelled() { public void onRebootCancelled() {
// if user presses button "Cancel", do not reboot the device, and toggles switch back // if user presses button "Cancel", do not reboot the device, and toggles switch back
final String currentGlesDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL); final String currentGlesDriver =
mSystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
if (TextUtils.equals(ANGLE_DRIVER_SUFFIX, currentGlesDriver)) { if (TextUtils.equals(ANGLE_DRIVER_SUFFIX, currentGlesDriver)) {
// if persist.graphics.egl = "angle", set the property value back to "" // if persist.graphics.egl = "angle", set the property value back to ""
GraphicsEnvironment.getInstance().toggleAngleAsSystemDriver(false); GraphicsEnvironment.getInstance().toggleAngleAsSystemDriver(false);

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2023 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.graphicsdriver;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.SystemProperties;
/**
* Wrapper interface to access {@link SystemProperties}.
*
* @hide
*/
interface GraphicsDriverSystemPropertiesWrapper {
/**
* Get the String value for the given {@code key}.
*
* @param key the key to lookup
* @param def the default value in case the property is not set or empty
* @return if the {@code key} isn't found, return {@code def} if it isn't null, or an empty
* string otherwise
*/
@NonNull
String get(@NonNull String key, @Nullable String def);
/**
* Set the value for the given {@code key} to {@code val}.
*
* @throws IllegalArgumentException if the {@code val} exceeds 91 characters
* @throws RuntimeException if the property cannot be set, for example, if it was blocked by
* SELinux. libc will log the underlying reason.
*/
void set(@NonNull String key, @Nullable String val);
}

View File

@@ -22,6 +22,7 @@ import android.app.backup.BackupDataInputStream;
import android.app.backup.BackupDataOutput; import android.app.backup.BackupDataOutput;
import android.app.backup.BackupHelper; import android.app.backup.BackupHelper;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager; import android.content.pm.IPackageManager;
import android.os.IDeviceIdleController; import android.os.IDeviceIdleController;
@@ -34,9 +35,11 @@ import android.util.Log;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend; import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -47,6 +50,8 @@ public final class BatteryBackupHelper implements BackupHelper {
/** An inditifier for {@link BackupHelper}. */ /** An inditifier for {@link BackupHelper}. */
public static final String TAG = "BatteryBackupHelper"; public static final String TAG = "BatteryBackupHelper";
private static final String DEVICE_IDLE_SERVICE = "deviceidle"; private static final String DEVICE_IDLE_SERVICE = "deviceidle";
private static final String BATTERY_OPTIMIZE_BACKUP_FILE_NAME =
"battery_optimize_backup_historical_logs";
static final String DELIMITER = ","; static final String DELIMITER = ",";
static final String DELIMITER_MODE = ":"; static final String DELIMITER_MODE = ":";
@@ -141,6 +146,7 @@ public final class BatteryBackupHelper implements BackupHelper {
int backupCount = 0; int backupCount = 0;
final StringBuilder builder = new StringBuilder(); final StringBuilder builder = new StringBuilder();
final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
final SharedPreferences sharedPreferences = getSharedPreferences(mContext);
// Converts application into the AppUsageState. // Converts application into the AppUsageState.
for (ApplicationInfo info : applications) { for (ApplicationInfo info : applications) {
final int mode = BatteryOptimizeUtils.getMode(appOps, info.uid, info.packageName); final int mode = BatteryOptimizeUtils.getMode(appOps, info.uid, info.packageName);
@@ -157,6 +163,9 @@ public final class BatteryBackupHelper implements BackupHelper {
info.packageName + DELIMITER_MODE + optimizationMode; info.packageName + DELIMITER_MODE + optimizationMode;
builder.append(packageOptimizeMode + DELIMITER); builder.append(packageOptimizeMode + DELIMITER);
Log.d(TAG, "backupOptimizationMode: " + packageOptimizeMode); Log.d(TAG, "backupOptimizationMode: " + packageOptimizeMode);
BatteryHistoricalLogUtil.writeLog(
sharedPreferences, Action.BACKUP, info.packageName,
/* actionDescription */ "mode: " + optimizationMode);
backupCount++; backupCount++;
} }
@@ -210,6 +219,18 @@ public final class BatteryBackupHelper implements BackupHelper {
restoreCount, (System.currentTimeMillis() - timestamp))); restoreCount, (System.currentTimeMillis() - timestamp)));
} }
/** Dump the app optimization mode backup history data. */
public static void dumpHistoricalData(Context context, PrintWriter writer) {
BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(
getSharedPreferences(context), writer);
}
@VisibleForTesting
static SharedPreferences getSharedPreferences(Context context) {
return context.getSharedPreferences(
BATTERY_OPTIMIZE_BACKUP_FILE_NAME, Context.MODE_PRIVATE);
}
private void restoreOptimizationMode( private void restoreOptimizationMode(
String packageName, @BatteryOptimizeUtils.OptimizationMode int mode) { String packageName, @BatteryOptimizeUtils.OptimizationMode int mode) {
final int uid = BatteryUtils.getInstance(mContext).getPackageUid(packageName); final int uid = BatteryUtils.getInstance(mContext).getPackageUid(packageName);

View File

@@ -37,40 +37,40 @@ public final class BatteryHistoricalLogUtil {
@VisibleForTesting @VisibleForTesting
static final int MAX_ENTRIES = 40; static final int MAX_ENTRIES = 40;
/** /** Writes a log entry for battery optimization mode. */
* Writes a log entry. static void writeLog(
* Context context, Action action, String packageName, String actionDescription) {
* <p>Keeps up to {@link #MAX_ENTRIES} in the log, once that number is exceeded, it prunes the writeLog(getSharedPreferences(context), action, packageName, actionDescription);
* oldest one. }
*/
static void writeLog(Context context, Action action, String pkg, String actionDescription) { static void writeLog(SharedPreferences sharedPreferences, Action action,
String packageName, String actionDescription) {
writeLog( writeLog(
context, sharedPreferences,
BatteryOptimizeHistoricalLogEntry.newBuilder() BatteryOptimizeHistoricalLogEntry.newBuilder()
.setPackageName(pkg) .setPackageName(packageName)
.setAction(action) .setAction(action)
.setActionDescription(actionDescription) .setActionDescription(actionDescription)
.setTimestamp(System.currentTimeMillis()) .setTimestamp(System.currentTimeMillis())
.build()); .build());
} }
private static void writeLog(Context context, BatteryOptimizeHistoricalLogEntry logEntry) { private static void writeLog(
SharedPreferences sharedPreferences = getSharedPreferences(context); SharedPreferences sharedPreferences, BatteryOptimizeHistoricalLogEntry logEntry) {
BatteryOptimizeHistoricalLog existingLog = BatteryOptimizeHistoricalLog existingLog =
parseLogFromString(sharedPreferences.getString(LOGS_KEY, "")); parseLogFromString(sharedPreferences.getString(LOGS_KEY, ""));
BatteryOptimizeHistoricalLog.Builder newLogBuilder = existingLog.toBuilder(); BatteryOptimizeHistoricalLog.Builder newLogBuilder = existingLog.toBuilder();
// Prune old entries // Prune old entries to limit the max logging data count.
if (existingLog.getLogEntryCount() >= MAX_ENTRIES) { if (existingLog.getLogEntryCount() >= MAX_ENTRIES) {
newLogBuilder.removeLogEntry(0); newLogBuilder.removeLogEntry(0);
} }
newLogBuilder.addLogEntry(logEntry); newLogBuilder.addLogEntry(logEntry);
String loggingContent =
Base64.encodeToString(newLogBuilder.build().toByteArray(), Base64.DEFAULT);
sharedPreferences sharedPreferences
.edit() .edit()
.putString( .putString(LOGS_KEY, loggingContent)
LOGS_KEY,
Base64.encodeToString(newLogBuilder.build().toByteArray(), Base64.DEFAULT))
.apply(); .apply();
} }
@@ -79,34 +79,36 @@ public final class BatteryHistoricalLogUtil {
storedLogs, BatteryOptimizeHistoricalLog.getDefaultInstance()); storedLogs, BatteryOptimizeHistoricalLog.getDefaultInstance());
} }
/** /** Prints the historical log that has previously been stored by this utility. */
* Prints the historical log that has previously been stored by this utility.
*/
public static void printBatteryOptimizeHistoricalLog(Context context, PrintWriter writer) { public static void printBatteryOptimizeHistoricalLog(Context context, PrintWriter writer) {
printBatteryOptimizeHistoricalLog(getSharedPreferences(context), writer);
}
/** Prints the historical log that has previously been stored by this utility. */
public static void printBatteryOptimizeHistoricalLog(
SharedPreferences sharedPreferences, PrintWriter writer) {
writer.println("Battery optimize state history:"); writer.println("Battery optimize state history:");
SharedPreferences sharedPreferences = getSharedPreferences(context);
BatteryOptimizeHistoricalLog existingLog = BatteryOptimizeHistoricalLog existingLog =
parseLogFromString(sharedPreferences.getString(LOGS_KEY, "")); parseLogFromString(sharedPreferences.getString(LOGS_KEY, ""));
List<BatteryOptimizeHistoricalLogEntry> logEntryList = existingLog.getLogEntryList(); List<BatteryOptimizeHistoricalLogEntry> logEntryList = existingLog.getLogEntryList();
if (logEntryList.isEmpty()) { if (logEntryList.isEmpty()) {
writer.println("\tNo past logs."); writer.println("\tnothing to dump");
} else { } else {
writer.println("0:RESTRICTED 1:UNRESTRICTED 2:OPTIMIZED 3:UNKNOWN"); writer.println("0:UNKNOWN 1:RESTRICTED 2:UNRESTRICTED 3:OPTIMIZED");
logEntryList.forEach(entry -> writer.println(toString(entry))); logEntryList.forEach(entry -> writer.println(toString(entry)));
} }
} }
/** /** Gets the unique key for logging. */
* Gets the unique key for logging, combined with package name, delimiter and user id. static String getPackageNameWithUserId(String packageName, int userId) {
*/ return packageName + ":" + userId;
static String getPackageNameWithUserId(String pkgName, int userId) {
return pkgName + ":" + userId;
} }
private static String toString(BatteryOptimizeHistoricalLogEntry entry) { private static String toString(BatteryOptimizeHistoricalLogEntry entry) {
return String.format("%s\tAction:%s\tEvent:%s\tTimestamp:%s", entry.getPackageName(), return String.format("%s\t%s\taction:%s\tevent:%s",
entry.getAction(), entry.getActionDescription(), ConvertUtils.utcToLocalTimeForLogging(entry.getTimestamp()),
ConvertUtils.utcToLocalTimeForLogging(entry.getTimestamp())); entry.getPackageName(), entry.getAction(),
entry.getActionDescription());
} }
@VisibleForTesting @VisibleForTesting

View File

@@ -299,9 +299,10 @@ public class BatteryInfo {
(double) PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */, (double) PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */,
true /* collapseTimeUnit */); true /* collapseTimeUnit */);
int resId = R.string.power_charging_duration; int resId = R.string.power_charging_duration;
info.remainingLabel = context.getString(R.string.power_remaining_charging_duration_only, info.remainingLabel = chargeTimeMs <= 0 ? null : context.getString(
timeString); R.string.power_remaining_charging_duration_only, timeString);
info.chargeLabel = context.getString(resId, info.batteryPercentString, timeString); info.chargeLabel = chargeTimeMs <= 0 ? info.batteryPercentString
: context.getString(resId, info.batteryPercentString, timeString);
} else if (dockDefenderMode == BatteryUtils.DockDefenderMode.FUTURE_BYPASS) { } else if (dockDefenderMode == BatteryUtils.DockDefenderMode.FUTURE_BYPASS) {
// Dock defender will be triggered in the future, charging will be optimized. // Dock defender will be triggered in the future, charging will be optimized.
info.chargeLabel = context.getString(R.string.power_charging_future_paused, info.chargeLabel = context.getString(R.string.power_charging_future_paused,

View File

@@ -24,7 +24,6 @@ import android.content.Intent;
import android.os.UserManager; import android.os.UserManager;
import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager;
import android.telephony.euicc.EuiccManager; import android.telephony.euicc.EuiccManager;
import android.util.Log;
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.LifecycleObserver;
@@ -135,6 +134,7 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController
return mContext.getString(R.string.mobile_network_tap_to_activate, displayName); return mContext.getString(R.string.mobile_network_tap_to_activate, displayName);
} else { } else {
return mSubInfoEntityList.stream() return mSubInfoEntityList.stream()
.sorted((e1, e2) -> Integer.compare(e1.simSlotIndex, e2.simSlotIndex))
.map(SubscriptionInfoEntity::getUniqueDisplayName) .map(SubscriptionInfoEntity::getUniqueDisplayName)
.collect(Collectors.joining(", ")); .collect(Collectors.joining(", "));
} }

View File

@@ -59,8 +59,10 @@ public class PrivacyDashboardFragment extends DashboardFragment {
SafetyCenterUtils.getEnterpriseOverrideStringForPrivacyEntries(); SafetyCenterUtils.getEnterpriseOverrideStringForPrivacyEntries();
for (int i = 0; i < privacyOverrideStrings.size(); i++) { for (int i = 0; i < privacyOverrideStrings.size(); i++) {
EnterpriseOverrideString overrideString = privacyOverrideStrings.get(i); EnterpriseOverrideString overrideString = privacyOverrideStrings.get(i);
replaceEnterpriseStringTitle(overrideString.getPreferenceKey(), replaceEnterpriseStringTitle(
overrideString.getOverrideKey(), overrideString.getResource()); overrideString.getPreferenceKey(),
overrideString.getOverrideKey(),
overrideString.getResource());
} }
} }
@@ -93,7 +95,9 @@ public class PrivacyDashboardFragment extends DashboardFragment {
@Override @Override
public List<SearchIndexableResource> getXmlResourcesToIndex( public List<SearchIndexableResource> getXmlResourcesToIndex(
Context context, boolean enabled) { Context context, boolean enabled) {
if (SafetyCenterManagerWrapper.get().isEnabled(context)) { // NOTE: This check likely should be moved to the super method. This is done
// here to avoid potentially undesired side effects for existing implementors.
if (!isPageSearchEnabled(context)) {
return null; return null;
} }
return super.getXmlResourcesToIndex(context, enabled); return super.getXmlResourcesToIndex(context, enabled);
@@ -120,5 +124,10 @@ public class PrivacyDashboardFragment extends DashboardFragment {
keys.add(KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS); keys.add(KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS);
return keys; return keys;
} }
@Override
protected boolean isPageSearchEnabled(Context context) {
return !SafetyCenterManagerWrapper.get().isEnabled(context);
}
}; };
} }

View File

@@ -77,21 +77,23 @@ public class MoreSecurityPrivacyFragment extends DashboardFragment {
SafetyCenterUtils.getEnterpriseOverrideStringForPrivacyEntries(); SafetyCenterUtils.getEnterpriseOverrideStringForPrivacyEntries();
for (int i = 0; i < privacyOverrideStrings.size(); i++) { for (int i = 0; i < privacyOverrideStrings.size(); i++) {
EnterpriseOverrideString overrideString = privacyOverrideStrings.get(i); EnterpriseOverrideString overrideString = privacyOverrideStrings.get(i);
replaceEnterpriseStringTitle(overrideString.getPreferenceKey(), replaceEnterpriseStringTitle(
overrideString.getOverrideKey(), overrideString.getResource()); overrideString.getPreferenceKey(),
overrideString.getOverrideKey(),
overrideString.getResource());
} }
List<EnterpriseOverrideString> securityOverrideStrings = List<EnterpriseOverrideString> securityOverrideStrings =
SafetyCenterUtils.getEnterpriseOverrideStringForSecurityEntries(); SafetyCenterUtils.getEnterpriseOverrideStringForSecurityEntries();
for (int i = 0; i < securityOverrideStrings.size(); i++) { for (int i = 0; i < securityOverrideStrings.size(); i++) {
EnterpriseOverrideString overrideString = securityOverrideStrings.get(i); EnterpriseOverrideString overrideString = securityOverrideStrings.get(i);
replaceEnterpriseStringTitle(overrideString.getPreferenceKey(), replaceEnterpriseStringTitle(
overrideString.getOverrideKey(), overrideString.getResource()); overrideString.getPreferenceKey(),
overrideString.getOverrideKey(),
overrideString.getResource());
} }
} }
/** /** see confirmPatternThenDisableAndClear */
* see confirmPatternThenDisableAndClear
*/
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (use(TrustAgentListPreferenceController.class) if (use(TrustAgentListPreferenceController.class)
@@ -117,10 +119,8 @@ public class MoreSecurityPrivacyFragment extends DashboardFragment {
controllers.addAll( controllers.addAll(
SafetyCenterUtils.getControllersForAdvancedSecurity(context, lifecycle, host)); SafetyCenterUtils.getControllersForAdvancedSecurity(context, lifecycle, host));
return controllers; return controllers;
} }
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.more_security_privacy_settings) { new BaseSearchIndexProvider(R.xml.more_security_privacy_settings) {
/** /**
@@ -130,7 +130,9 @@ public class MoreSecurityPrivacyFragment extends DashboardFragment {
@Override @Override
public List<SearchIndexableResource> getXmlResourcesToIndex( public List<SearchIndexableResource> getXmlResourcesToIndex(
Context context, boolean enabled) { Context context, boolean enabled) {
if (!SafetyCenterManagerWrapper.get().isEnabled(context)) { // NOTE: This check likely should be moved to the super method. This is done
// here to avoid potentially undesired side effects for existing implementors.
if (!isPageSearchEnabled(context)) {
return null; return null;
} }
return super.getXmlResourcesToIndex(context, enabled); return super.getXmlResourcesToIndex(context, enabled);
@@ -157,5 +159,10 @@ public class MoreSecurityPrivacyFragment extends DashboardFragment {
keys.add(KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS); keys.add(KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS);
return keys; return keys;
} }
@Override
protected boolean isPageSearchEnabled(Context context) {
return SafetyCenterManagerWrapper.get().isEnabled(context);
}
}; };
} }

View File

@@ -58,8 +58,10 @@ public class SecurityAdvancedSettings extends DashboardFragment {
SafetyCenterUtils.getEnterpriseOverrideStringForSecurityEntries(); SafetyCenterUtils.getEnterpriseOverrideStringForSecurityEntries();
for (int i = 0; i < securityOverrideStrings.size(); i++) { for (int i = 0; i < securityOverrideStrings.size(); i++) {
EnterpriseOverrideString overrideString = securityOverrideStrings.get(i); EnterpriseOverrideString overrideString = securityOverrideStrings.get(i);
replaceEnterpriseStringTitle(overrideString.getPreferenceKey(), replaceEnterpriseStringTitle(
overrideString.getOverrideKey(), overrideString.getResource()); overrideString.getPreferenceKey(),
overrideString.getOverrideKey(),
overrideString.getResource());
} }
} }
@@ -77,8 +79,7 @@ public class SecurityAdvancedSettings extends DashboardFragment {
return CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS; return CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS;
} else { } else {
final SecuritySettingsFeatureProvider securitySettingsFeatureProvider = final SecuritySettingsFeatureProvider securitySettingsFeatureProvider =
FeatureFactory.getFactory(context) FeatureFactory.getFactory(context).getSecuritySettingsFeatureProvider();
.getSecuritySettingsFeatureProvider();
if (securitySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment()) { if (securitySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment()) {
return securitySettingsFeatureProvider.getAlternativeAdvancedSettingsCategoryKey(); return securitySettingsFeatureProvider.getAlternativeAdvancedSettingsCategoryKey();
@@ -103,9 +104,7 @@ public class SecurityAdvancedSettings extends DashboardFragment {
return buildPreferenceControllers(context, getSettingsLifecycle(), this /* host*/); return buildPreferenceControllers(context, getSettingsLifecycle(), this /* host*/);
} }
/** /** see confirmPatternThenDisableAndClear */
* see confirmPatternThenDisableAndClear
*/
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (use(TrustAgentListPreferenceController.class) if (use(TrustAgentListPreferenceController.class)
@@ -119,14 +118,12 @@ public class SecurityAdvancedSettings extends DashboardFragment {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
} }
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context, private static List<AbstractPreferenceController> buildPreferenceControllers(
Lifecycle lifecycle, DashboardFragment host) { Context context, Lifecycle lifecycle, DashboardFragment host) {
return SafetyCenterUtils.getControllersForAdvancedSecurity(context, lifecycle, host); return SafetyCenterUtils.getControllersForAdvancedSecurity(context, lifecycle, host);
} }
/** /** For Search. Please keep it in sync when updating "createPreferenceHierarchy()" */
* For Search. Please keep it in sync when updating "createPreferenceHierarchy()"
*/
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.security_advanced_settings) { new BaseSearchIndexProvider(R.xml.security_advanced_settings) {
/** /**
@@ -134,19 +131,26 @@ public class SecurityAdvancedSettings extends DashboardFragment {
* page, and we don't want to index these entries. * page, and we don't want to index these entries.
*/ */
@Override @Override
public List<SearchIndexableResource> getXmlResourcesToIndex(Context context, public List<SearchIndexableResource> getXmlResourcesToIndex(
boolean enabled) { Context context, boolean enabled) {
if (SafetyCenterManagerWrapper.get().isEnabled(context)) { // NOTE: This check likely should be moved to the super method. This is done
// here to avoid potentially undesired side effects for existing implementors.
if (!isPageSearchEnabled(context)) {
return null; return null;
} }
return super.getXmlResourcesToIndex(context, enabled); return super.getXmlResourcesToIndex(context, enabled);
} }
@Override @Override
public List<AbstractPreferenceController> createPreferenceControllers(Context public List<AbstractPreferenceController> createPreferenceControllers(
context) { Context context) {
return buildPreferenceControllers(context, null /* lifecycle */, return buildPreferenceControllers(
null /* host*/); context, null /* lifecycle */, null /* host*/);
}
@Override
protected boolean isPageSearchEnabled(Context context) {
return !SafetyCenterManagerWrapper.get().isEnabled(context);
} }
}; };
} }

View File

@@ -28,7 +28,6 @@ import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@@ -83,6 +82,7 @@ import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.drawable.CircleFramedDrawable; import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.search.SearchIndexableRaw; import com.android.settingslib.search.SearchIndexableRaw;
import com.android.settingslib.users.CreateUserDialogController;
import com.android.settingslib.users.EditUserInfoController; import com.android.settingslib.users.EditUserInfoController;
import com.android.settingslib.users.GrantAdminDialogController; import com.android.settingslib.users.GrantAdminDialogController;
import com.android.settingslib.users.UserCreatingDialog; import com.android.settingslib.users.UserCreatingDialog;
@@ -119,6 +119,7 @@ public class UserSettings extends SettingsPreferenceFragment
/** UserId of the user being removed */ /** UserId of the user being removed */
private static final String SAVE_REMOVING_USER = "removing_user"; private static final String SAVE_REMOVING_USER = "removing_user";
private static final String SAVE_CREATE_USER = "create_user";
private static final String KEY_USER_LIST = "user_list"; private static final String KEY_USER_LIST = "user_list";
private static final String KEY_USER_ME = "user_me"; private static final String KEY_USER_ME = "user_me";
@@ -171,9 +172,6 @@ public class UserSettings extends SettingsPreferenceFragment
static final int RESULT_GUEST_REMOVED = 100; static final int RESULT_GUEST_REMOVED = 100;
private static final String KEY_ADD_USER_LONG_MESSAGE_DISPLAYED =
"key_add_user_long_message_displayed";
private static final String KEY_TITLE = "title"; private static final String KEY_TITLE = "title";
private static final String KEY_SUMMARY = "summary"; private static final String KEY_SUMMARY = "summary";
@@ -222,6 +220,8 @@ public class UserSettings extends SettingsPreferenceFragment
new GrantAdminDialogController(); new GrantAdminDialogController();
private EditUserInfoController mEditUserInfoController = private EditUserInfoController mEditUserInfoController =
new EditUserInfoController(Utils.FILE_PROVIDER_AUTHORITY); new EditUserInfoController(Utils.FILE_PROVIDER_AUTHORITY);
private CreateUserDialogController mCreateUserDialogController =
new CreateUserDialogController(Utils.FILE_PROVIDER_AUTHORITY);
private AddUserWhenLockedPreferenceController mAddUserWhenLockedPreferenceController; private AddUserWhenLockedPreferenceController mAddUserWhenLockedPreferenceController;
private GuestTelephonyPreferenceController mGuestTelephonyPreferenceController; private GuestTelephonyPreferenceController mGuestTelephonyPreferenceController;
private RemoveGuestOnExitPreferenceController mRemoveGuestOnExitPreferenceController; private RemoveGuestOnExitPreferenceController mRemoveGuestOnExitPreferenceController;
@@ -233,7 +233,7 @@ public class UserSettings extends SettingsPreferenceFragment
private CharSequence mPendingUserName; private CharSequence mPendingUserName;
private Drawable mPendingUserIcon; private Drawable mPendingUserIcon;
private boolean mGrantAdmin; private boolean mPendingUserIsAdmin;
// A place to cache the generated default avatar // A place to cache the generated default avatar
private Drawable mDefaultIconDrawable; private Drawable mDefaultIconDrawable;
@@ -348,8 +348,12 @@ public class UserSettings extends SettingsPreferenceFragment
if (icicle.containsKey(SAVE_REMOVING_USER)) { if (icicle.containsKey(SAVE_REMOVING_USER)) {
mRemovingUserId = icicle.getInt(SAVE_REMOVING_USER); mRemovingUserId = icicle.getInt(SAVE_REMOVING_USER);
} }
if (icicle.containsKey(SAVE_CREATE_USER)) {
mCreateUserDialogController.onRestoreInstanceState(icicle);
} else {
mEditUserInfoController.onRestoreInstanceState(icicle); mEditUserInfoController.onRestoreInstanceState(icicle);
} }
}
mUserCaps = UserCapabilities.create(activity); mUserCaps = UserCapabilities.create(activity);
mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE); mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE);
@@ -440,7 +444,12 @@ public class UserSettings extends SettingsPreferenceFragment
@Override @Override
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(Bundle outState) {
if (mCreateUserDialogController.isActive()) {
outState.putBoolean(SAVE_CREATE_USER, mCreateUserDialogController.isActive());
mCreateUserDialogController.onSaveInstanceState(outState);
} else {
mEditUserInfoController.onSaveInstanceState(outState); mEditUserInfoController.onSaveInstanceState(outState);
}
outState.putInt(SAVE_REMOVING_USER, mRemovingUserId); outState.putInt(SAVE_REMOVING_USER, mRemovingUserId);
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
} }
@@ -448,6 +457,7 @@ public class UserSettings extends SettingsPreferenceFragment
@Override @Override
public void startActivityForResult(Intent intent, int requestCode) { public void startActivityForResult(Intent intent, int requestCode) {
mEditUserInfoController.startingActivityForResult(); mEditUserInfoController.startingActivityForResult();
mCreateUserDialogController.startingActivityForResult();
super.startActivityForResult(intent, requestCode); super.startActivityForResult(intent, requestCode);
} }
@@ -562,6 +572,7 @@ public class UserSettings extends SettingsPreferenceFragment
&& resultCode == RESULT_GUEST_REMOVED) { && resultCode == RESULT_GUEST_REMOVED) {
scheduleGuestCreation(); scheduleGuestCreation();
} else { } else {
mCreateUserDialogController.onActivityResult(requestCode, resultCode, data);
mEditUserInfoController.onActivityResult(requestCode, resultCode, data); mEditUserInfoController.onActivityResult(requestCode, resultCode, data);
} }
} }
@@ -704,37 +715,12 @@ public class UserSettings extends SettingsPreferenceFragment
.setPositiveButton(android.R.string.ok, null) .setPositiveButton(android.R.string.ok, null)
.create(); .create();
case DIALOG_ADD_USER: { case DIALOG_ADD_USER: {
final SharedPreferences preferences = getActivity().getPreferences( synchronized (mUserLock) {
Context.MODE_PRIVATE); mPendingUserName = getString(
final boolean longMessageDisplayed = preferences.getBoolean( com.android.settingslib.R.string.user_new_user_name);
KEY_ADD_USER_LONG_MESSAGE_DISPLAYED, false); mPendingUserIcon = null;
final int messageResId = longMessageDisplayed
? com.android.settingslib.R.string.user_add_user_message_short
: com.android.settingslib.R.string.user_add_user_message_long;
Dialog dlg = new AlertDialog.Builder(context)
.setTitle(com.android.settingslib.R.string.user_add_user_title)
.setMessage(messageResId)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (!longMessageDisplayed) {
preferences.edit().putBoolean(
KEY_ADD_USER_LONG_MESSAGE_DISPLAYED,
true).apply();
} }
if (UserManager.isMultipleAdminEnabled()) { return buildAddUserDialog(USER_TYPE_USER);
showDialog(DIALOG_GRANT_ADMIN);
} else {
showDialog(DIALOG_USER_PROFILE_EDITOR_ADD_USER);
}
}
})
.setNegativeButton(android.R.string.cancel, null)
.create();
return dlg;
}
case DIALOG_GRANT_ADMIN: {
return buildGrantAdminDialog();
} }
case DIALOG_CHOOSE_USER_TYPE: { case DIALOG_CHOOSE_USER_TYPE: {
List<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>(); List<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>();
@@ -919,17 +905,14 @@ public class UserSettings extends SettingsPreferenceFragment
private Dialog buildAddUserDialog(int userType) { private Dialog buildAddUserDialog(int userType) {
Dialog d; Dialog d;
synchronized (mUserLock) { synchronized (mUserLock) {
d = mEditUserInfoController.createDialog( d = mCreateUserDialogController.createDialog(
getActivity(), getActivity(),
this::startActivityForResult, this::startActivityForResult,
null, UserManager.isMultipleAdminEnabled(),
mPendingUserName.toString(), (userName, userIcon, isAdmin) -> {
getString(userType == USER_TYPE_USER
? com.android.settingslib.R.string.user_info_settings_title
: com.android.settingslib.R.string.profile_info_settings_title),
(userName, userIcon) -> {
mPendingUserIcon = userIcon; mPendingUserIcon = userIcon;
mPendingUserName = userName; mPendingUserName = userName;
mPendingUserIsAdmin = isAdmin;
addUserNow(userType); addUserNow(userType);
}, },
() -> { () -> {
@@ -943,26 +926,6 @@ public class UserSettings extends SettingsPreferenceFragment
return d; return d;
} }
private Dialog buildGrantAdminDialog() {
return mGrantAdminDialogController.createDialog(
getActivity(),
(grantAdmin) -> {
mGrantAdmin = grantAdmin;
if (mGrantAdmin) {
mMetricsFeatureProvider.action(getActivity(),
SettingsEnums.ACTION_GRANT_ADMIN_FROM_SETTINGS_CREATION_DIALOG);
} else {
mMetricsFeatureProvider.action(getActivity(),
SettingsEnums.ACTION_NOT_GRANT_ADMIN_FROM_SETTINGS_CREATION_DIALOG);
}
showDialog(DIALOG_USER_PROFILE_EDITOR_ADD_USER);
},
() -> {
mGrantAdmin = false;
}
);
}
@Override @Override
public int getDialogMetricsCategory(int dialogId) { public int getDialogMetricsCategory(int dialogId) {
switch (dialogId) { switch (dialogId) {
@@ -1065,7 +1028,7 @@ public class UserSettings extends SettingsPreferenceFragment
userName, userName,
mUserManager.USER_TYPE_FULL_SECONDARY, mUserManager.USER_TYPE_FULL_SECONDARY,
0); 0);
if (mGrantAdmin) { if (mPendingUserIsAdmin) {
mUserManager.setUserAdmin(user.id); mUserManager.setUserAdmin(user.id);
} }
} else { } else {
@@ -1665,6 +1628,9 @@ public class UserSettings extends SettingsPreferenceFragment
synchronized (mUserLock) { synchronized (mUserLock) {
mRemovingUserId = -1; mRemovingUserId = -1;
updateUserList(); updateUserList();
if (mCreateUserDialogController.isActive()) {
mCreateUserDialogController.clear();
}
} }
} }

View File

@@ -45,6 +45,8 @@ import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import com.android.settings.core.FeatureFlags; import com.android.settings.core.FeatureFlags;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.wifi.repository.WifiHotspotRepository;
import com.android.settings.wifi.tether.WifiTetherAutoOffPreferenceController; import com.android.settings.wifi.tether.WifiTetherAutoOffPreferenceController;
import com.android.settings.wifi.tether.WifiTetherSecurityPreferenceController; import com.android.settings.wifi.tether.WifiTetherSecurityPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -94,6 +96,8 @@ public class AllInOneTetherSettingsTest {
mContext = spy(RuntimeEnvironment.application); mContext = spy(RuntimeEnvironment.application);
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
when(FakeFeatureFactory.setupForTest().getWifiFeatureProvider().getWifiHotspotRepository())
.thenReturn(mock(WifiHotspotRepository.class));
doReturn(mWifiManager).when(mContext).getSystemService(WifiManager.class); doReturn(mWifiManager).when(mContext).getSystemService(WifiManager.class);
doReturn(mConnectivityManager) doReturn(mConnectivityManager)
.when(mContext).getSystemService(Context.CONNECTIVITY_SERVICE); .when(mContext).getSystemService(Context.CONNECTIVITY_SERVICE);

View File

@@ -19,20 +19,26 @@ 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.util.AttributeSet; import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.preference.PreferenceViewHolder;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R; import com.android.settings.R;
import com.android.settingslib.Utils;
import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Spy; import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule; import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class FlashNotificationsPreviewPreferenceTest { public class FlashNotificationsPreviewPreferenceTest {
@@ -41,37 +47,46 @@ public class FlashNotificationsPreviewPreferenceTest {
public MockitoRule mMockitoRule = MockitoJUnit.rule(); public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Spy @Spy
private final Context mContext = ApplicationProvider.getApplicationContext(); private final Context mContext = ApplicationProvider.getApplicationContext();
private final AttributeSet mAttributeSet = Robolectric.buildAttributeSet().build(); private FlashNotificationsPreviewPreference mFlashNotificationsPreviewPreference;
private PreferenceViewHolder mPreferenceViewHolder;
@Test @Before
public void constructor_assertLayoutResource_P00() { public void setUp() {
FlashNotificationsPreviewPreference preference = new FlashNotificationsPreviewPreference( mPreferenceViewHolder = PreferenceViewHolder.createInstanceForTests(
mContext); LayoutInflater.from(mContext).inflate(
assertThat(preference.getLayoutResource()) R.layout.flash_notification_preview_preference, null));
.isEqualTo(R.layout.flash_notification_preview_preference); mFlashNotificationsPreviewPreference = new FlashNotificationsPreviewPreference(mContext);
} }
@Test @Test
public void constructor_assertLayoutResource_P01() { public void setEnabled_true_verifyEnabledUi() {
FlashNotificationsPreviewPreference preference = new FlashNotificationsPreviewPreference( @ColorInt final int textColorEnabled = ((TextView) mPreferenceViewHolder.findViewById(
mContext, mAttributeSet); android.R.id.title)).getCurrentTextColor();
assertThat(preference.getLayoutResource())
.isEqualTo(R.layout.flash_notification_preview_preference); mFlashNotificationsPreviewPreference.setEnabled(true);
mFlashNotificationsPreviewPreference.onBindViewHolder(mPreferenceViewHolder);
final View frame = mPreferenceViewHolder.findViewById(R.id.frame);
final int backgroundResId = Shadows.shadowOf(frame.getBackground()).getCreatedFromResId();
assertThat(backgroundResId).isEqualTo(R.drawable.settingslib_switch_bar_bg_on);
final TextView title = (TextView) mPreferenceViewHolder.findViewById(android.R.id.title);
assertThat(title.getAlpha()).isEqualTo(1f);
assertThat(title.getCurrentTextColor()).isEqualTo(textColorEnabled);
} }
@Test @Test
public void constructor_assertLayoutResource_P02() { public void setEnabled_false_verifyDisabledUi() {
FlashNotificationsPreviewPreference preference = new FlashNotificationsPreviewPreference( @ColorInt final int textColorDisabled = Utils.getColorAttrDefaultColor(mContext,
mContext, mAttributeSet, 0); android.R.attr.textColorPrimary);
assertThat(preference.getLayoutResource())
.isEqualTo(R.layout.flash_notification_preview_preference);
}
@Test mFlashNotificationsPreviewPreference.setEnabled(false);
public void constructor_assertLayoutResource_P03() { mFlashNotificationsPreviewPreference.onBindViewHolder(mPreferenceViewHolder);
FlashNotificationsPreviewPreference preference = new FlashNotificationsPreviewPreference(
mContext, mAttributeSet, 0, 0); final View frame = mPreferenceViewHolder.findViewById(R.id.frame);
assertThat(preference.getLayoutResource()) final int backgroundResId = Shadows.shadowOf(frame.getBackground()).getCreatedFromResId();
.isEqualTo(R.layout.flash_notification_preview_preference); assertThat(backgroundResId).isEqualTo(R.drawable.switch_bar_bg_disabled);
final TextView title = (TextView) mPreferenceViewHolder.findViewById(android.R.id.title);
assertThat(title.getAlpha()).isEqualTo(0.38f);
assertThat(title.getCurrentTextColor()).isEqualTo(textColorDisabled);
} }
} }

View File

@@ -53,7 +53,6 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle; import android.os.Bundle;
import android.os.CancellationSignal; import android.os.CancellationSignal;
import android.os.Vibrator; import android.os.Vibrator;
import android.util.FeatureFlagUtils;
import android.view.Display; import android.view.Display;
import android.view.Surface; import android.view.Surface;
import android.view.View; import android.view.View;
@@ -203,8 +202,6 @@ public class FingerprintEnrollEnrollingTest {
@Test @Test
public void fingerprintUdfpsOverlayEnrollment_showOverlayPortrait() { public void fingerprintUdfpsOverlayEnrollment_showOverlayPortrait() {
FeatureFlagUtils.setEnabled(mContext,
FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL); initializeActivityFor(TYPE_UDFPS_OPTICAL);
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0); when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
@@ -216,8 +213,6 @@ public class FingerprintEnrollEnrollingTest {
@Test @Test
public void fingerprintUdfpsOverlayEnrollment_showOverlayLandscape() { public void fingerprintUdfpsOverlayEnrollment_showOverlayLandscape() {
FeatureFlagUtils.setEnabled(mContext,
FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL); initializeActivityFor(TYPE_UDFPS_OPTICAL);
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_90); when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_90);
@@ -229,8 +224,6 @@ public class FingerprintEnrollEnrollingTest {
@Test @Test
public void fingerprintUdfpsOverlayEnrollment_usesCorrectProgressBarFillColor() { public void fingerprintUdfpsOverlayEnrollment_usesCorrectProgressBarFillColor() {
FeatureFlagUtils.setEnabled(mContext,
FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL); initializeActivityFor(TYPE_UDFPS_OPTICAL);
final TypedArray ta = mActivity.obtainStyledAttributes(null, final TypedArray ta = mActivity.obtainStyledAttributes(null,
R.styleable.BiometricsEnrollView, R.attr.biometricsEnrollStyle, R.styleable.BiometricsEnrollView, R.attr.biometricsEnrollStyle,
@@ -250,9 +243,7 @@ public class FingerprintEnrollEnrollingTest {
@Test @Test
public void fingerprintUdfpsOverlayEnrollment_checkViewOverlapPortrait() { public void fingerprintUdfpsOverlayEnrollment_checkViewOverlapPortrait() {
FeatureFlagUtils.setEnabled(mContext, when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_90);
initializeActivityFor(TYPE_UDFPS_OPTICAL); initializeActivityFor(TYPE_UDFPS_OPTICAL);
final GlifLayout defaultLayout = mActivity.findViewById(R.id.setup_wizard_layout); final GlifLayout defaultLayout = mActivity.findViewById(R.id.setup_wizard_layout);
@@ -320,10 +311,36 @@ public class FingerprintEnrollEnrollingTest {
.intersect(rectUdfpsEnrollView.get())).isFalse(); .intersect(rectUdfpsEnrollView.get())).isFalse();
} }
@Test
public void fingerprintUdfpsOverlayEnrollment_descriptionViewGoneWithOverlap() {
initializeActivityWithoutCreate(TYPE_UDFPS_OPTICAL);
doReturn(true).when(mActivity).hasOverlap(any(), any());
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
createActivity();
final GlifLayout defaultLayout = spy(mActivity.findViewById(R.id.setup_wizard_layout));
final TextView descriptionTextView = defaultLayout.getDescriptionTextView();
defaultLayout.getViewTreeObserver().dispatchOnDraw();
assertThat(descriptionTextView.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void fingerprintUdfpsOverlayEnrollment_descriptionViewVisibleWithoutOverlap() {
initializeActivityWithoutCreate(TYPE_UDFPS_OPTICAL);
doReturn(false).when(mActivity).hasOverlap(any(), any());
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
createActivity();
final GlifLayout defaultLayout = spy(mActivity.findViewById(R.id.setup_wizard_layout));
final TextView descriptionTextView = defaultLayout.getDescriptionTextView();
defaultLayout.getViewTreeObserver().dispatchOnDraw();
assertThat(descriptionTextView.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test @Test
public void forwardEnrollProgressEvents() { public void forwardEnrollProgressEvents() {
FeatureFlagUtils.setEnabled(mContext,
FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL); initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity); EnrollListener listener = new EnrollListener(mActivity);
@@ -337,8 +354,6 @@ public class FingerprintEnrollEnrollingTest {
@Test @Test
public void forwardEnrollHelpEvents() { public void forwardEnrollHelpEvents() {
FeatureFlagUtils.setEnabled(mContext,
FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL); initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity); EnrollListener listener = new EnrollListener(mActivity);
@@ -352,8 +367,6 @@ public class FingerprintEnrollEnrollingTest {
@Test @Test
public void forwardEnrollAcquiredEvents() { public void forwardEnrollAcquiredEvents() {
FeatureFlagUtils.setEnabled(mContext,
FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL); initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity); EnrollListener listener = new EnrollListener(mActivity);
@@ -368,8 +381,6 @@ public class FingerprintEnrollEnrollingTest {
@Test @Test
public void forwardEnrollPointerDownEvents() { public void forwardEnrollPointerDownEvents() {
FeatureFlagUtils.setEnabled(mContext,
FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL); initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity); EnrollListener listener = new EnrollListener(mActivity);
@@ -383,8 +394,6 @@ public class FingerprintEnrollEnrollingTest {
@Test @Test
public void forwardEnrollPointerUpEvents() { public void forwardEnrollPointerUpEvents() {
FeatureFlagUtils.setEnabled(mContext,
FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL); initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity); EnrollListener listener = new EnrollListener(mActivity);

View File

@@ -20,8 +20,11 @@ import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFP
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment; import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment;
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.ADD_FINGERPRINT_REQUEST; import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.ADD_FINGERPRINT_REQUEST;
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.CHOOSE_LOCK_GENERIC_REQUEST;
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.KEY_FINGERPRINT_ADD; import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.KEY_FINGERPRINT_ADD;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
@@ -54,6 +57,7 @@ import com.android.settings.biometrics.BiometricsSplitScreenDialog;
import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowFragment; import com.android.settings.testutils.shadow.ShadowFragment;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowSettingsPreferenceFragment; import com.android.settings.testutils.shadow.ShadowSettingsPreferenceFragment;
import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settings.testutils.shadow.ShadowUtils;
@@ -63,6 +67,7 @@ import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule; import org.mockito.junit.MockitoRule;
@@ -74,7 +79,7 @@ import java.util.ArrayList;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowSettingsPreferenceFragment.class, ShadowUtils.class, ShadowFragment.class, @Config(shadows = {ShadowSettingsPreferenceFragment.class, ShadowUtils.class, ShadowFragment.class,
ShadowUserManager.class}) ShadowUserManager.class, ShadowLockPatternUtils.class})
public class FingerprintSettingsFragmentTest { public class FingerprintSettingsFragmentTest {
private FingerprintSettingsFragment mFragment; private FingerprintSettingsFragment mFragment;
private Context mContext; private Context mContext;
@@ -92,10 +97,62 @@ public class FingerprintSettingsFragmentTest {
doReturn(true).when(mFingerprintManager).isHardwareDetected(); doReturn(true).when(mFingerprintManager).isHardwareDetected();
ShadowUtils.setFingerprintManager(mFingerprintManager); ShadowUtils.setFingerprintManager(mFingerprintManager);
FakeFeatureFactory.setupForTest(); FakeFeatureFactory.setupForTest();
}
@After
public void tearDown() {
ShadowUtils.reset();
}
@Test
public void testAddFingerprint_inFullScreen_noDialog() {
setUpFragment(false);
// Click "Add Fingerprint"
final Preference preference = new Preference(mContext);
preference.setKey(KEY_FINGERPRINT_ADD);
mFragment.onPreferenceTreeClick(preference);
verify(mFragment).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST));
verify(mFragmentTransaction, never()).add(any(),
eq(BiometricsSplitScreenDialog.class.getName()));
}
@Test
public void testAddFingerprint_inMultiWindow_showsDialog() {
setUpFragment(false);
doReturn(true).when(mActivity).isInMultiWindowMode();
// Click "Add Fingerprint"
final Preference preference = new Preference(mContext);
preference.setKey(KEY_FINGERPRINT_ADD);
mFragment.onPreferenceTreeClick(preference);
verify(mFragment, times(0)).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST));
verify(mFragmentTransaction).add(any(), eq(BiometricsSplitScreenDialog.class.getName()));
}
@Test
public void testChooseLockKeyForFingerprint() {
setUpFragment(true);
ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(
Intent.class);
verify(mFragment).startActivityForResult(intentArgumentCaptor.capture(),
eq(CHOOSE_LOCK_GENERIC_REQUEST));
Intent intent = intentArgumentCaptor.getValue();
assertThat(intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
false)).isTrue();
}
private void setUpFragment(boolean showChooseLock) {
Intent intent = new Intent(); Intent intent = new Intent();
if (!showChooseLock) {
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 1L); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 1L);
}
mActivity = spy(Robolectric.buildActivity(FragmentActivity.class, intent).get()); mActivity = spy(Robolectric.buildActivity(FragmentActivity.class, intent).get());
mContext = spy(ApplicationProvider.getApplicationContext()); mContext = spy(ApplicationProvider.getApplicationContext());
@@ -112,49 +169,12 @@ public class FingerprintSettingsFragmentTest {
doNothing().when(mFragment).startActivityForResult(any(Intent.class), anyInt()); doNothing().when(mFragment).startActivityForResult(any(Intent.class), anyInt());
setSensor(); setSensor();
}
@After
public void tearDown() {
ShadowUtils.reset();
}
@Test
public void testAddFingerprint_inFullScreen_noDialog() {
// Start fragment // Start fragment
mFragment.onAttach(mContext); mFragment.onAttach(mContext);
mFragment.onCreate(null); mFragment.onCreate(null);
mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY); mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY);
mFragment.onResume(); mFragment.onResume();
// Click "Add Fingerprint"
final Preference preference = new Preference(mContext);
preference.setKey(KEY_FINGERPRINT_ADD);
mFragment.onPreferenceTreeClick(preference);
verify(mFragment).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST));
verify(mFragmentTransaction, never()).add(any(),
eq(BiometricsSplitScreenDialog.class.getName()));
}
@Test
public void testAddFingerprint_inMultiWindow_showsDialog() {
// Start fragment
mFragment.onAttach(mContext);
mFragment.onCreate(null);
mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY);
mFragment.onResume();
doReturn(true).when(mActivity).isInMultiWindowMode();
// Click "Add Fingerprint"
final Preference preference = new Preference(mContext);
preference.setKey(KEY_FINGERPRINT_ADD);
mFragment.onPreferenceTreeClick(preference);
verify(mFragment, times(0)).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST));
verify(mFragmentTransaction).add(any(), eq(BiometricsSplitScreenDialog.class.getName()));
} }
private void setSensor() { private void setSensor() {

View File

@@ -56,6 +56,9 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import java.util.HashSet;
import java.util.Set;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowEntityHeaderController.class, ShadowDeviceConfig.class}) @Config(shadows = {ShadowEntityHeaderController.class, ShadowDeviceConfig.class})
public class AdvancedBluetoothDetailsHeaderControllerTest { public class AdvancedBluetoothDetailsHeaderControllerTest {
@@ -380,40 +383,68 @@ public class AdvancedBluetoothDetailsHeaderControllerTest {
SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "true", true); SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "true", true);
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
.thenReturn("true".getBytes()); .thenReturn("true".getBytes());
Set<CachedBluetoothDevice> cacheBluetoothDevices = new HashSet<>();
when(mCachedDevice.getMemberDevice()).thenReturn(cacheBluetoothDevices);
mController.onStart(); mController.onStart();
verify(mCachedDevice).registerCallback(mController);
verify(mBluetoothAdapter).addOnMetadataChangedListener(mBluetoothDevice, verify(mBluetoothAdapter).addOnMetadataChangedListener(mBluetoothDevice,
mContext.getMainExecutor(), mController.mMetadataListener); mContext.getMainExecutor(), mController.mMetadataListener);
} }
@Test @Test
public void onStop_isRegisterCallback_unregisterCallback() { public void onStart_notAvailable_notNeedToRegisterCallback() {
mController.mIsRegisterCallback = true;
mController.onStop();
verify(mBluetoothAdapter).removeOnMetadataChangedListener(mBluetoothDevice,
mController.mMetadataListener);
}
@Test
public void onStart_notAvailable_registerCallback() {
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
.thenReturn("false".getBytes()); .thenReturn("false".getBytes());
mController.onStart(); mController.onStart();
verify(mCachedDevice, never()).registerCallback(mController);
verify(mBluetoothAdapter, never()).addOnMetadataChangedListener(mBluetoothDevice, verify(mBluetoothAdapter, never()).addOnMetadataChangedListener(mBluetoothDevice,
mContext.getMainExecutor(), mController.mMetadataListener); mContext.getMainExecutor(), mController.mMetadataListener);
} }
@Test @Test
public void onStop_notRegisterCallback_unregisterCallback() { public void onStart_isAvailableButNoBluetoothDevice_notNeedToRegisterCallback() {
mController.mIsRegisterCallback = false; DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI,
SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "true", true);
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
.thenReturn("true".getBytes());
when(mCachedDevice.getDevice()).thenReturn(null);
Set<CachedBluetoothDevice> cacheBluetoothDevices = new HashSet<>();
when(mCachedDevice.getMemberDevice()).thenReturn(cacheBluetoothDevices);
mController.onStart();
verify(mCachedDevice, never()).registerCallback(mController);
verify(mBluetoothAdapter, never()).addOnMetadataChangedListener(mBluetoothDevice,
mContext.getMainExecutor(), mController.mMetadataListener);
}
@Test
public void onStop_availableAndHasBluetoothDevice_unregisterCallback() {
onStart_isAvailable_registerCallback();
mController.onStop(); mController.onStop();
verify(mCachedDevice).unregisterCallback(mController);
verify(mBluetoothAdapter).removeOnMetadataChangedListener(mBluetoothDevice,
mController.mMetadataListener);
}
@Test
public void onStop_noBluetoothDevice_noNeedToUnregisterCallback() {
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI,
SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "true", true);
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
.thenReturn("true".getBytes());
when(mCachedDevice.getDevice()).thenReturn(null);
mController.onStart();
mController.onStop();
verify(mCachedDevice, never()).unregisterCallback(mController);
verify(mBluetoothAdapter, never()).removeOnMetadataChangedListener(mBluetoothDevice, verify(mBluetoothAdapter, never()).removeOnMetadataChangedListener(mBluetoothDevice,
mController.mMetadataListener); mController.mMetadataListener);
} }

View File

@@ -81,9 +81,10 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerTest {
// since GraphicsEnvironment is mocked in Robolectric test environment, // since GraphicsEnvironment is mocked in Robolectric test environment,
// we will override the system property persist.graphics.egl as if it is changed by // we will override the system property persist.graphics.egl as if it is changed by
// mGraphicsEnvironment.toggleAngleAsSystemDriver(true). // mGraphicsEnvironment.toggleAngleAsSystemDriver(true).
// TODO: b/270994705 yuxinhu:
// add test coverage to test mGraphicsEnvironment.toggleAngleAsSystemDriver() // for test that actually verifies mGraphicsEnvironment.toggleAngleAsSystemDriver(true)
// works properly on Android devices / emulators. // on a device/emulator, please refer to
// GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest
ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, ANGLE_DRIVER_SUFFIX); ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, ANGLE_DRIVER_SUFFIX);
mController.onPreferenceChange(mPreference, true); mController.onPreferenceChange(mPreference, true);
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL); final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
@@ -97,9 +98,10 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerTest {
// since GraphicsEnvironment is mocked in Robolectric test environment, // since GraphicsEnvironment is mocked in Robolectric test environment,
// we will override the system property persist.graphics.egl as if it is changed by // we will override the system property persist.graphics.egl as if it is changed by
// mGraphicsEnvironment.toggleAngleAsSystemDriver(false). // mGraphicsEnvironment.toggleAngleAsSystemDriver(false).
// TODO: b/270994705 yuxinhu:
// add test coverage to test mGraphicsEnvironment.toggleAngleAsSystemDriver() // for test that actually verifies mGraphicsEnvironment.toggleAngleAsSystemDriver(true)
// works properly on Android devices / emulators. // on a device/emulator, please refer to
// GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest
ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, ""); ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
mController.onPreferenceChange(mPreference, false); mController.onPreferenceChange(mPreference, false);
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL); final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
@@ -124,20 +126,14 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerTest {
@Test @Test
public void updateState_angleSupported_angleUsed_preferenceShouldBeChecked() { public void updateState_angleSupported_angleUsed_preferenceShouldBeChecked() {
ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true"); ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
// TODO: b/270994705 yuxinhu:
// add test coverage to test mGraphicsEnvironment.toggleAngleAsSystemDriver()
// works properly on Android devices / emulators.
ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, ANGLE_DRIVER_SUFFIX); ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, ANGLE_DRIVER_SUFFIX);
mController.updateState(mPreference); mController.updateState(mPreference);
verify(mPreference).setChecked(true); //false verify(mPreference).setChecked(true);
} }
@Test @Test
public void updateState_angleSupported_angleNotUsed_preferenceShouldNotBeChecked() { public void updateState_angleSupported_angleNotUsed_preferenceShouldNotBeChecked() {
ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true"); ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
// TODO: b/270994705 yuxinhu:
// add test coverage to test mGraphicsEnvironment.toggleAngleAsSystemDriver(false)
// works properly on Android devices / emulators.
ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, ""); ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
mController.updateState(mPreference); mController.updateState(mPreference);
verify(mPreference).setChecked(false); verify(mPreference).setChecked(false);

View File

@@ -70,6 +70,8 @@ import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements; import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter; import org.robolectric.annotation.Resetter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -84,6 +86,8 @@ public final class BatteryBackupHelperTest {
private static final int UID1 = 1; private static final int UID1 = 1;
private Context mContext; private Context mContext;
private PrintWriter mPrintWriter;
private StringWriter mStringWriter;
private BatteryBackupHelper mBatteryBackupHelper; private BatteryBackupHelper mBatteryBackupHelper;
@Mock @Mock
@@ -109,6 +113,8 @@ public final class BatteryBackupHelperTest {
public void setUp() throws Exception { public void setUp() throws Exception {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application); mContext = spy(RuntimeEnvironment.application);
mStringWriter = new StringWriter();
mPrintWriter = new PrintWriter(mStringWriter);
doReturn(mContext).when(mContext).getApplicationContext(); doReturn(mContext).when(mContext).getApplicationContext();
doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class); doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class);
doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
@@ -126,6 +132,7 @@ public final class BatteryBackupHelperTest {
@After @After
public void resetShadows() { public void resetShadows() {
ShadowUserHandle.reset(); ShadowUserHandle.reset();
BatteryBackupHelper.getSharedPreferences(mContext).edit().clear().apply();
} }
@Test @Test
@@ -216,6 +223,8 @@ public final class BatteryBackupHelperTest {
// 2 for UNRESTRICTED mode and 1 for RESTRICTED mode. // 2 for UNRESTRICTED mode and 1 for RESTRICTED mode.
final String expectedResult = PACKAGE_NAME1 + ":2," + PACKAGE_NAME2 + ":1,"; final String expectedResult = PACKAGE_NAME1 + ":2," + PACKAGE_NAME2 + ":1,";
verifyBackupData(expectedResult); verifyBackupData(expectedResult);
verifyDumpHistoryData("com.android.testing.1\taction:BACKUP\tevent:mode: 2");
verifyDumpHistoryData("com.android.testing.2\taction:BACKUP\tevent:mode: 1");
} }
@Test @Test
@@ -232,6 +241,7 @@ public final class BatteryBackupHelperTest {
// "com.android.testing.2" for RESTRICTED mode. // "com.android.testing.2" for RESTRICTED mode.
final String expectedResult = PACKAGE_NAME2 + ":1,"; final String expectedResult = PACKAGE_NAME2 + ":1,";
verifyBackupData(expectedResult); verifyBackupData(expectedResult);
verifyDumpHistoryData("com.android.testing.2\taction:BACKUP\tevent:mode: 1");
} }
@Test @Test
@@ -248,6 +258,7 @@ public final class BatteryBackupHelperTest {
// "com.android.testing.2" for RESTRICTED mode. // "com.android.testing.2" for RESTRICTED mode.
final String expectedResult = PACKAGE_NAME2 + ":1,"; final String expectedResult = PACKAGE_NAME2 + ":1,";
verifyBackupData(expectedResult); verifyBackupData(expectedResult);
verifyDumpHistoryData("com.android.testing.2\taction:BACKUP\tevent:mode: 1");
} }
@Test @Test
@@ -357,6 +368,11 @@ public final class BatteryBackupHelperTest {
doReturn(dataKey).when(mBackupDataInputStream).getKey(); doReturn(dataKey).when(mBackupDataInputStream).getKey();
} }
private void verifyDumpHistoryData(String expectedResult) {
BatteryBackupHelper.dumpHistoricalData(mContext, mPrintWriter);
assertThat(mStringWriter.toString().contains(expectedResult)).isTrue();
}
private void verifyBackupData(String expectedResult) throws Exception { private void verifyBackupData(String expectedResult) throws Exception {
final byte[] expectedBytes = expectedResult.getBytes(); final byte[] expectedBytes = expectedResult.getBytes();
final ArgumentCaptor<byte[]> captor = ArgumentCaptor.forClass(byte[].class); final ArgumentCaptor<byte[]> captor = ArgumentCaptor.forClass(byte[].class);

View File

@@ -49,7 +49,7 @@ public final class BatteryHistoricalLogUtilTest {
@Test @Test
public void printHistoricalLog_withDefaultLogs() { public void printHistoricalLog_withDefaultLogs() {
BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter);
assertThat(mTestStringWriter.toString()).contains("No past logs"); assertThat(mTestStringWriter.toString()).contains("nothing to dump");
} }
@Test @Test
@@ -58,7 +58,7 @@ public final class BatteryHistoricalLogUtilTest {
BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter);
assertThat(mTestStringWriter.toString()).contains( assertThat(mTestStringWriter.toString()).contains(
"pkg1\tAction:APPLY\tEvent:logs\tTimestamp:"); "pkg1\taction:APPLY\tevent:logs");
} }
@Test @Test

View File

@@ -133,18 +133,12 @@ public class MobileNetworkSummaryControllerTest {
assertThat(mController.isAvailable()).isFalse(); assertThat(mController.isAvailable()).isFalse();
} }
@Ignore
@Test @Test
public void getSummary_noSubscriptions_correctSummaryAndClickHandler() { public void getSummary_noSubscriptions_returnSummaryCorrectly() {
mController.displayPreference(mPreferenceScreen); mController.displayPreference(mPreferenceScreen);
mController.onResume(); mController.onResume();
assertThat(mController.getSummary()).isEqualTo("Add a network");
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); assertThat(mController.getSummary()).isEqualTo("Add a network");
doNothing().when(mContext).startActivity(intentCaptor.capture());
mPreference.getOnPreferenceClickListener().onPreferenceClick(mPreference);
assertThat(intentCaptor.getValue().getAction()).isEqualTo(
EuiccManager.ACTION_PROVISION_EMBEDDED_SUBSCRIPTION);
} }
@Test @Test
@@ -300,15 +294,13 @@ public class MobileNetworkSummaryControllerTest {
assertThat(captor.getValue()).isFalse(); assertThat(captor.getValue()).isFalse();
} }
@Ignore
@Test @Test
public void onResume_noSubscriptionEsimDisabled_isDisabled() { public void onAvailableSubInfoChanged_noSubscriptionEsimDisabled_isDisabled() {
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
SubscriptionUtil.setAvailableSubscriptionsForTesting(null);
when(mEuiccManager.isEnabled()).thenReturn(false); when(mEuiccManager.isEnabled()).thenReturn(false);
mController.displayPreference(mPreferenceScreen); mController.displayPreference(mPreferenceScreen);
mController.onResume(); mController.onAvailableSubInfoChanged(null);
assertThat(mPreference.isEnabled()).isFalse(); assertThat(mPreference.isEnabled()).isFalse();
} }

View File

@@ -30,6 +30,8 @@ import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericF
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_DEVICE_PASSWORD_REQUIREMENT_ONLY; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_DEVICE_PASSWORD_REQUIREMENT_ONLY;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_IS_CALLING_APP_ADMIN; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_IS_CALLING_APP_ADMIN;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
@@ -126,7 +128,9 @@ public class ChooseLockGenericTest {
when(mFaceManager.isHardwareDetected()).thenReturn(true); when(mFaceManager.isHardwareDetected()).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true); when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn( when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn(
false); true);
ShadowUtils.setFingerprintManager(mFingerprintManager);
ShadowUtils.setFaceManager(mFaceManager);
} }
@After @After
@@ -540,35 +544,63 @@ public class ChooseLockGenericTest {
@Test @Test
public void updatePreferenceText_supportBiometrics_showFaceAndFingerprint() { public void updatePreferenceText_supportBiometrics_showFaceAndFingerprint() {
ShadowLockPatternUtils.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW); ShadowStorageManager.setIsFileEncrypted(false);
final PasswordPolicy policy = new PasswordPolicy();
policy.quality = PASSWORD_QUALITY_ALPHABETIC;
ShadowLockPatternUtils.setRequestedProfilePasswordMetrics(policy.getMinMetrics());
final Intent intent = new Intent().putExtra(EXTRA_KEY_FOR_BIOMETRICS, true); final Intent intent = new Intent().putExtra(EXTRA_KEY_FOR_BIOMETRICS, true);
initActivity(intent); initActivity(intent);
final Intent passwordIntent = mFragment.getLockPatternIntent();
assertThat(passwordIntent.getIntExtra(ChooseLockPassword.EXTRA_KEY_MIN_COMPLEXITY,
PASSWORD_COMPLEXITY_NONE)).isEqualTo(PASSWORD_COMPLEXITY_LOW);
final String supportFingerprint = capitalize(mActivity.getResources().getString( final String supportFingerprint = capitalize(mActivity.getResources().getString(
R.string.security_settings_fingerprint)); R.string.security_settings_fingerprint));
final String supportFace = capitalize(mActivity.getResources().getString( final String supportFace = capitalize(mActivity.getResources().getString(
R.string.keywords_face_settings)); R.string.keywords_face_settings));
String pinTitle =
(String) mFragment.findPreference(ScreenLockType.PIN.preferenceKey).getTitle();
String patternTitle =
(String) mFragment.findPreference(ScreenLockType.PATTERN.preferenceKey).getTitle();
String passwordTitle =
(String) mFragment.findPreference(ScreenLockType.PASSWORD.preferenceKey).getTitle();
assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains( assertThat(pinTitle).contains(supportFingerprint);
supportFingerprint); assertThat(pinTitle).contains(supportFace);
assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains( assertThat(patternTitle).contains(supportFingerprint);
supportFace); assertThat(patternTitle).contains(supportFace);
assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).contains( assertThat(passwordTitle).contains(supportFingerprint);
supportFingerprint); assertThat(passwordTitle).contains(supportFace);
assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).contains( }
supportFace);
assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).contains( @Test
supportFingerprint); public void updatePreferenceText_supportFingerprint_showFingerprint() {
assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).contains( ShadowStorageManager.setIsFileEncrypted(false);
supportFace); final Intent intent = new Intent().putExtra(EXTRA_KEY_FOR_FINGERPRINT, true);
initActivity(intent);
mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
assertThat(mFragment.findPreference(ScreenLockType.PIN.preferenceKey).getTitle()).isEqualTo(
mFragment.getString(R.string.fingerprint_unlock_set_unlock_pin));
assertThat(mFragment.findPreference(
ScreenLockType.PATTERN.preferenceKey).getTitle()).isEqualTo(
mFragment.getString(R.string.fingerprint_unlock_set_unlock_pattern));
assertThat(mFragment.findPreference(
ScreenLockType.PASSWORD.preferenceKey).getTitle()).isEqualTo(
mFragment.getString(R.string.fingerprint_unlock_set_unlock_password));
}
@Test
public void updatePreferenceText_supportFace_showFace() {
ShadowStorageManager.setIsFileEncrypted(false);
final Intent intent = new Intent().putExtra(EXTRA_KEY_FOR_FACE, true);
initActivity(intent);
mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
assertThat(mFragment.findPreference(ScreenLockType.PIN.preferenceKey).getTitle()).isEqualTo(
mFragment.getString(R.string.face_unlock_set_unlock_pin));
assertThat(mFragment.findPreference(
ScreenLockType.PATTERN.preferenceKey).getTitle()).isEqualTo(
mFragment.getString(R.string.face_unlock_set_unlock_pattern));
assertThat(mFragment.findPreference(
ScreenLockType.PASSWORD.preferenceKey).getTitle()).isEqualTo(
mFragment.getString(R.string.face_unlock_set_unlock_password));
} }
private void initActivity(@Nullable Intent intent) { private void initActivity(@Nullable Intent intent) {

View File

@@ -0,0 +1,325 @@
/*
* Copyright (C) 2023 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.graphicsdriver;
import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.ANGLE_DRIVER_SUFFIX;
import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.Injector;
import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.PROPERTY_PERSISTENT_GRAPHICS_EGL;
import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.PROPERTY_RO_GFX_ANGLE_SUPPORTED;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Looper;
import android.os.SystemProperties;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.development.DevelopmentSettingsDashboardFragment;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest {
private Context mContext;
private SwitchPreference mPreference;
private GraphicsDriverEnableAngleAsSystemDriverController mController;
@Mock
private DevelopmentSettingsDashboardFragment mFragment;
@Mock
private GraphicsDriverSystemPropertiesWrapper mSystemPropertiesMock;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
if (Looper.myLooper() == null) {
Looper.prepare();
}
mContext = ApplicationProvider.getApplicationContext();
// Construct a GraphicsDriverEnableAngleAsSystemDriverController with two Overrides:
// 1) Override the mSystemProperties with mSystemPropertiesMock,
// so we can force the SystemProperties with values we need to run tests.
// 2) Override the showRebootDialog() to do nothing.
// We do not need to pop up the reboot dialog in the test.
mController = new GraphicsDriverEnableAngleAsSystemDriverController(
mContext, mFragment, new Injector(){
@Override
public GraphicsDriverSystemPropertiesWrapper createSystemPropertiesWrapper() {
return mSystemPropertiesMock;
}
}) {
@Override
void showRebootDialog() {
// do nothing
}
};
final PreferenceManager preferenceManager = new PreferenceManager(mContext);
final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
mPreference = new SwitchPreference(mContext);
mPreference.setKey(mController.getPreferenceKey());
screen.addPreference(mPreference);
mController.displayPreference(screen);
}
@Test
public void onPreferenceChange_switchOn_shouldEnableAngleAsSystemDriver() {
// Add a callback when SystemProperty changes.
// This allows the thread to wait until
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
final CountDownLatch countDownLatch = new CountDownLatch(1);
Runnable countDown = new Runnable() {
@Override
public void run() {
countDownLatch.countDown();
}
};
SystemProperties.addChangeCallback(countDown);
// Test onPreferenceChange(true) updates the persist.graphics.egl to "angle"
mController.onPreferenceChange(mPreference, true);
try {
countDownLatch.await(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo(ANGLE_DRIVER_SUFFIX);
// Done with the test, remove the callback
SystemProperties.removeChangeCallback(countDown);
}
@Test
public void onPreferenceChange_switchOff_shouldDisableAngleAsSystemDriver() {
// Add a callback when SystemProperty changes.
// This allows the thread to wait until
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
final CountDownLatch countDownLatch = new CountDownLatch(1);
Runnable countDown = new Runnable() {
@Override
public void run() {
countDownLatch.countDown();
}
};
SystemProperties.addChangeCallback(countDown);
// Test onPreferenceChange(false) updates the persist.graphics.egl to ""
mController.onPreferenceChange(mPreference, false);
try {
countDownLatch.await(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo("");
// Done with the test, remove the callback
SystemProperties.removeChangeCallback(countDown);
}
@Test
public void updateState_angleNotSupported_PreferenceShouldDisabled() {
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any())).thenReturn("");
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isFalse();
}
@Test
public void updateState_angleNotSupported_PreferenceShouldNotBeChecked() {
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
.thenReturn("");
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void updateState_angleSupported_PreferenceShouldEnabled() {
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
.thenReturn("true");
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isTrue();
}
@Test
public void updateState_angleSupported_angleIsSystemGLESDriver_PreferenceShouldBeChecked() {
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
.thenReturn("true");
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
.thenReturn(ANGLE_DRIVER_SUFFIX);
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void
updateState_angleSupported_angleIsNotSystemGLESDriver_PreferenceShouldNotBeChecked() {
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
.thenReturn("true");
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
.thenReturn("");
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void onDeveloperOptionSwitchEnabled_angleSupported_PreferenceShouldEnabled() {
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
.thenReturn("true");
mController.onDeveloperOptionsSwitchEnabled();
assertThat(mPreference.isEnabled()).isTrue();
}
@Test
public void onDeveloperOptionSwitchEnabled_angleNotSupported_PrefenceShouldDisabled() {
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
.thenReturn("false");
mController.onDeveloperOptionsSwitchEnabled();
assertThat(mPreference.isEnabled()).isFalse();
}
@Test
public void onDeveloperOptionSwitchDisabled_angleIsNotSystemGLESDriver() {
// Add a callback when SystemProperty changes.
// This allows the thread to wait until
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
final CountDownLatch countDownLatch = new CountDownLatch(1);
Runnable countDown = new Runnable() {
@Override
public void run() {
countDownLatch.countDown();
}
};
SystemProperties.addChangeCallback(countDown);
// Test that onDeveloperOptionSwitchDisabled,
// persist.graphics.egl updates to ""
mController.onDeveloperOptionsSwitchDisabled();
try {
countDownLatch.await(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo("");
// Done with the test, remove the callback
SystemProperties.removeChangeCallback(countDown);
}
@Test
public void onDeveloperOptionSwitchDisabled_PreferenceShouldNotBeChecked() {
mController.onDeveloperOptionsSwitchDisabled();
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void onDeveloperOptionSwitchDisabled_PreferenceShouldDisabled() {
mController.onDeveloperOptionsSwitchDisabled();
assertThat(mPreference.isEnabled()).isFalse();
}
@Test
public void onRebootCancelled_ToggleSwitchFromOnToOff() {
// Add a callback when SystemProperty changes.
// This allows the thread to wait until
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
final CountDownLatch countDownLatch = new CountDownLatch(1);
Runnable countDown = new Runnable() {
@Override
public void run() {
countDownLatch.countDown();
}
};
SystemProperties.addChangeCallback(countDown);
// Test that if the current persist.graphics.egl is "angle",
// when reboot is cancelled, persist.graphics.egl is changed back to "",
// and switch is set to unchecked.
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
.thenReturn(ANGLE_DRIVER_SUFFIX);
mController.onRebootCancelled();
try {
countDownLatch.await(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo("");
assertThat(mPreference.isChecked()).isFalse();
// Done with the test, remove the callback.
SystemProperties.removeChangeCallback(countDown);
}
@Test
public void onRebootCancelled_ToggleSwitchFromOffToOn() {
// Add a callback when SystemProperty changes.
// This allows the thread to wait until
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
final CountDownLatch countDownLatch = new CountDownLatch(1);
Runnable countDown = new Runnable() {
@Override
public void run() {
countDownLatch.countDown();
}
};
SystemProperties.addChangeCallback(countDown);
// Test that if the current persist.graphics.egl is "",
// when reboot is cancelled, persist.graphics.egl is changed back to "angle",
// and switch is set to checked.
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
.thenReturn("");
mController.onRebootCancelled();
try {
countDownLatch.await(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo(ANGLE_DRIVER_SUFFIX);
assertThat(mPreference.isChecked()).isTrue();
// Done with the test, remove the callback.
SystemProperties.removeChangeCallback(countDown);
}
}