Snap for 9509200 from 25bb53260b to udc-release

Change-Id: Ifa072d0bb240308639a7bb52c79ca020a2548911
This commit is contained in:
Android Build Coastguard Worker
2023-01-20 02:27:06 +00:00
18 changed files with 484 additions and 139 deletions

View File

@@ -234,11 +234,11 @@
<!-- Dialog text shown when the user tries to skip setting up a screen lock, warning them of potential consequences of not doing so. (phone) [CHAR LIMIT=NONE] -->
<string name="lock_screen_intro_skip_dialog_text" product="default">Device protection features won\u2019t be turned on. You won\u2019t be able to prevent others from using this phone if it\u2019s lost or stolen.</string>
<!-- Message shown in SFPS enrollment dialog to locate the sensor (tablet) [CHAR LIMIT=NONE]-->
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.\n\nPressing the power button turns off the screen.</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.</string>
<!-- Message shown in SFPS enrollment dialog to locate the sensor (device) [CHAR LIMIT=NONE]-->
<string name="security_settings_sfps_enroll_find_sensor_message" product="device">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device.\n\nPressing the power button turns off the screen.</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device.</string>
<!-- Message shown in SFPS enrollment dialog to locate the sensor (default) [CHAR LIMIT=NONE]-->
<string name="security_settings_sfps_enroll_find_sensor_message" product="default">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone.\n\nPressing the power button turns off the screen.</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone.</string>
<!-- Message shown in fingerprint enrollment dialog once enrollment is completed (tablet) [CHAR LIMIT=NONE] -->
<string name="security_settings_fingerprint_enroll_finish_v2_message" product="tablet">Now you can use your fingerprint to unlock your tablet or verify it\u2019s you, like when you sign in to apps or approve a purchase</string>
<!-- Message shown in fingerprint enrollment dialog once enrollment is completed (device) [CHAR LIMIT=NONE] -->

View File

@@ -0,0 +1,35 @@
<!--
Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="@color/battery_usage_system_icon_color">
<path
android:fillColor="@android:color/white"
android:pathData="M17,6l-1.41,1.41L20.17,12l-4.58,4.59L17,18l6,-6zM8.41,7.41L7,6l-6,6 6,6 1.41,-1.41L3.83,12z"/>
<path
android:fillColor="@android:color/white"
android:pathData="M8,12m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
<path
android:fillColor="@android:color/white"
android:pathData="M12,12m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
<path
android:fillColor="@android:color/white"
android:pathData="M16,12m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
</vector>

View File

@@ -578,7 +578,13 @@
<!-- The option list for switch screen resolution -->
<string-array name="config_screen_resolution_options_strings" translatable="false">
<item>@string/screen_resolution_option_high</item>
<item>@string/screen_resolution_option_full</item>
<item>@string/screen_resolution_option_highest</item>
</string-array>
<!-- The option summary list for screen resolution -->
<string-array name="config_screen_resolution_summaries_strings" translatable="false">
<item>@string/screen_resolution_summary_high</item>
<item>@string/screen_resolution_summary_highest</item>
</string-array>
<!-- Whether to aggregate for network selection list-->

View File

@@ -826,12 +826,6 @@
<string name="security_settings_udfps_enroll_find_sensor_title">How to set up your fingerprint</string>
<!-- Message shown in fingerprint enrollment dialog to locate the sensor -->
<string name="security_settings_fingerprint_enroll_find_sensor_message">It\u2019s on the back of your phone. Use your index finger.</string>
<!-- Message shown in SFPS enrollment dialog to locate the sensor (tablet) [CHAR LIMIT=NONE]-->
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet.</string>
<!-- Message shown in SFPS enrollment dialog to locate the sensor (device) [CHAR LIMIT=NONE]-->
<string name="security_settings_sfps_enroll_find_sensor_message" product="device">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device.</string>
<!-- Message shown in SFPS enrollment dialog to locate the sensor (default) [CHAR LIMIT=NONE]-->
<string name="security_settings_sfps_enroll_find_sensor_message" product="default">The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone.</string>
<!-- Message shown in UDFPS enrollment dialog to locate the sensor [CHAR LIMIT=NONE]-->
<string name="security_settings_udfps_enroll_find_sensor_message">The fingerprint sensor is on your screen. You\u2019ll capture your fingerprint on the next screen.</string>
<!-- Button for starting fingerprint enrollment. [CHAR LIMIT=10]-->
@@ -2142,10 +2136,14 @@
<!-- Display settings screen, screen resolution settings title [CHAR LIMIT=30] -->
<string name="screen_resolution_title">Screen resolution</string>
<!-- Display settings screen, screen resolution option for high resolution [CHAR LIMIT=45] -->
<!-- Display settings screen, screen resolution option for "FHD+" [CHAR LIMIT=45] -->
<string name="screen_resolution_option_high">High resolution</string>
<!-- Display settings screen, screen resolution option for full resolution [CHAR LIMIT=45] -->
<string name="screen_resolution_option_full">Full resolution</string>
<!-- Display settings screen, screen resolution option for "QHD+" [CHAR LIMIT=45] -->
<string name="screen_resolution_option_highest">Full resolution</string>
<!-- Display settings screen, "FHD+" screen resolution summary [CHAR LIMIT=NONE] -->
<string name="screen_resolution_summary_high">1080p FHD+</string>
<!-- Display settings screen, "QHD+" screen resolution summary [CHAR LIMIT=NONE] -->
<string name="screen_resolution_summary_highest">1440p QHD+</string>
<!-- The footer message for switch screen resolution [CHAR LIMIT=NONE] -->
<string name="screen_resolution_footer">Full resolution uses more of your battery. Switching your resolution may cause some apps to restart.</string>
<!-- Message announced to a11y users when they selected one resolution [CHAR LIMIT=NONE] -->

View File

@@ -45,6 +45,14 @@ public abstract class BiometricEnrollSidecar extends InstrumentedFragment {
* @param isAcquiredGood whether the fingerprint image was good.
*/
default void onAcquired(boolean isAcquiredGood) { }
/**
* Called when a pointer down event has occurred.
*/
default void onPointerDown(int sensorId) { }
/**
* Called when a pointer up event has occurred.
*/
default void onPointerUp(int sensorId) { }
}
private int mEnrollmentSteps = -1;
@@ -118,6 +126,32 @@ public abstract class BiometricEnrollSidecar extends InstrumentedFragment {
}
}
private class QueuedPointerDown extends QueuedEvent {
private final int sensorId;
public QueuedPointerDown(int sensorId) {
this.sensorId = sensorId;
}
@Override
public void send(Listener listener) {
listener.onPointerDown(sensorId);
}
}
private class QueuedPointerUp extends QueuedEvent {
private final int sensorId;
public QueuedPointerUp(int sensorId) {
this.sensorId = sensorId;
}
@Override
public void send(Listener listener) {
listener.onPointerUp(sensorId);
}
}
private final Runnable mTimeoutRunnable = new Runnable() {
@Override
public void run() {
@@ -215,6 +249,22 @@ public abstract class BiometricEnrollSidecar extends InstrumentedFragment {
}
}
protected void onPointerDown(int sensorId) {
if (mListener != null) {
mListener.onPointerDown(sensorId);
} else {
mQueuedEvents.add(new QueuedPointerDown(sensorId));
}
}
protected void onPointerUp(int sensorId) {
if (mListener != null) {
mListener.onPointerUp(sensorId);
} else {
mQueuedEvents.add(new QueuedPointerUp(sensorId));
}
}
public void setListener(Listener listener) {
mListener = listener;
if (mListener != null) {

View File

@@ -82,6 +82,7 @@ import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieCompositionFactory;
import com.airbnb.lottie.LottieProperty;
import com.airbnb.lottie.model.KeyPath;
import com.google.android.setupcompat.template.FooterActionButton;
import com.google.android.setupcompat.template.FooterBarMixin;
import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupcompat.util.WizardManagerHelper;
@@ -101,6 +102,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
private static final String TAG = "FingerprintEnrollEnrolling";
static final String TAG_SIDECAR = "sidecar";
static final String TAG_UDFPS_HELPER = "udfps_helper";
static final String KEY_STATE_CANCELED = "is_canceled";
static final String KEY_STATE_PREVIOUS_ROTATION = "previous_rotation";
@@ -353,6 +355,24 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
.build()
);
if (FeatureFlagUtils.isEnabled(getApplicationContext(),
FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) {
// Remove the space view and make the width of footer button container WRAP_CONTENT
// to avoid hiding the udfps view progress bar bottom.
final LinearLayout buttonContainer = mFooterBarMixin.getButtonContainer();
View spaceView = null;
for (int i = 0; i < buttonContainer.getChildCount(); i++) {
if (!(buttonContainer.getChildAt(i) instanceof FooterActionButton)) {
spaceView = buttonContainer.getChildAt(i);
break;
}
}
if (spaceView != null) {
spaceView.setVisibility(View.GONE);
buttonContainer.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
}
}
final LayerDrawable fingerprintDrawable = mProgressBar != null
? (LayerDrawable) mProgressBar.getBackground() : null;
if (fingerprintDrawable != null) {
@@ -867,6 +887,20 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
}
}
@Override
public void onPointerDown(int sensorId) {
if (mUdfpsEnrollHelper != null) {
mUdfpsEnrollHelper.onPointerDown(sensorId);
}
}
@Override
public void onPointerUp(int sensorId) {
if (mUdfpsEnrollHelper != null) {
mUdfpsEnrollHelper.onPointerUp(sensorId);
}
}
private void updateProgress(boolean animate) {
if (mSidecar == null || !mSidecar.isEnrolling()) {
Log.d(TAG, "Enrollment not started yet");
@@ -1195,7 +1229,16 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
udfpsProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
udfpsEnrollView.setOverlayParams(params);
mUdfpsEnrollHelper = new UdfpsEnrollHelper(getApplicationContext(), mFingerprintManager);
mUdfpsEnrollHelper = (UdfpsEnrollHelper) getSupportFragmentManager().findFragmentByTag(
FingerprintEnrollEnrolling.TAG_UDFPS_HELPER);
if (mUdfpsEnrollHelper == null) {
mUdfpsEnrollHelper = new UdfpsEnrollHelper(getApplicationContext(),
mFingerprintManager);
getSupportFragmentManager().beginTransaction()
.add(mUdfpsEnrollHelper, FingerprintEnrollEnrolling.TAG_UDFPS_HELPER)
.commitAllowingStateLoss();
}
udfpsEnrollView.setEnrollHelper(mUdfpsEnrollHelper);
return udfpsEnrollView;

View File

@@ -122,6 +122,16 @@ public class FingerprintEnrollSidecar extends BiometricEnrollSidecar {
public void onEnrollmentError(int errMsgId, CharSequence errString) {
FingerprintEnrollSidecar.super.onEnrollmentError(errMsgId, errString);
}
@Override
public void onPointerDown(int sensorId) {
FingerprintEnrollSidecar.super.onPointerDown(sensorId);
}
@Override
public void onPointerUp(int sensorId) {
FingerprintEnrollSidecar.super.onPointerUp(sensorId);
}
};
@Override

View File

@@ -646,6 +646,7 @@ public class FingerprintSettings extends SubSettings {
if (mAuthenticateSidecar != null) {
mAuthenticateSidecar.setListener(null);
mAuthenticateSidecar.stopAuthentication();
mHandler.removeCallbacks(mFingerprintLockoutReset);
}
}

View File

@@ -96,6 +96,16 @@ public class FingerprintUpdater {
public void onAcquired(boolean isAcquiredGood) {
mCallback.onAcquired(isAcquiredGood);
}
@Override
public void onPointerDown(int sensorId) {
mCallback.onPointerDown(sensorId);
}
@Override
public void onPointerUp(int sensorId) {
mCallback.onPointerUp(sensorId);
}
}
/**

View File

@@ -22,19 +22,22 @@ import android.content.Context;
import android.graphics.PointF;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.util.TypedValue;
import android.view.accessibility.AccessibilityManager;
import com.android.settings.core.InstrumentedFragment;
import java.util.ArrayList;
import java.util.List;
/**
* Helps keep track of enrollment state and animates the progress bar accordingly.
*/
public class UdfpsEnrollHelper {
public class UdfpsEnrollHelper extends InstrumentedFragment {
private static final String TAG = "UdfpsEnrollHelper";
private static final String SCALE_OVERRIDE =
@@ -50,6 +53,10 @@ public class UdfpsEnrollHelper {
void onEnrollmentHelp(int remaining, int totalSteps);
void onAcquired(boolean animateIfLastStepGood);
void onPointerDown(int sensorId);
void onPointerUp(int sensorId);
}
@NonNull
@@ -124,6 +131,17 @@ public class UdfpsEnrollHelper {
}
}
@Override
public int getMetricsCategory() {
return 0;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
void onEnrollmentProgress(int totalSteps, int remaining) {
if (mTotalSteps == -1) {
mTotalSteps = totalSteps;
@@ -144,7 +162,7 @@ public class UdfpsEnrollHelper {
}
void onEnrollmentHelp() {
if (mListener != null && mTotalSteps != -1) {
if (mListener != null) {
mListener.onEnrollmentHelp(mRemainingSteps, mTotalSteps);
}
}
@@ -155,6 +173,18 @@ public class UdfpsEnrollHelper {
}
}
void onPointerDown(int sensorId) {
if (mListener != null) {
mListener.onPointerDown(sensorId);
}
}
void onPointerUp(int sensorId) {
if (mListener != null) {
mListener.onPointerUp(sensorId);
}
}
void setListener(UdfpsEnrollHelper.Listener listener) {
mListener = listener;

View File

@@ -88,10 +88,22 @@ public class UdfpsEnrollView extends FrameLayout implements UdfpsEnrollHelper.Li
@Override
public void onAcquired(boolean animateIfLastStepGood) {
mHandler.post(() -> {
onFingerUp();
if (animateIfLastStepGood) mFingerprintProgressDrawable.onLastStepAcquired();
});
}
@Override
public void onPointerDown(int sensorId) {
onFingerDown();
}
@Override
public void onPointerUp(int sensorId) {
onFingerUp();
}
void setOverlayParams(UdfpsOverlayParams params) {
mOverlayParams = params;
@@ -99,7 +111,7 @@ public class UdfpsEnrollView extends FrameLayout implements UdfpsEnrollHelper.Li
mProgressBarRadius =
(int) (mOverlayParams.getScaleFactor() * getContext().getResources().getInteger(
R.integer.config_udfpsEnrollProgressBar));
mSensorRect = mOverlayParams.getSensorBounds();
mSensorRect = new Rect(mOverlayParams.getSensorBounds());
onSensorRectUpdated();
});
@@ -123,7 +135,7 @@ public class UdfpsEnrollView extends FrameLayout implements UdfpsEnrollHelper.Li
private void updateDimensions() {
// Original sensorBounds assume portrait mode.
Rect rotatedBounds = mOverlayParams.getSensorBounds();
final Rect rotatedBounds = mOverlayParams.getSensorBounds();
int rotation = mOverlayParams.getRotation();
if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
RotationUtils.rotateBounds(
@@ -137,33 +149,42 @@ public class UdfpsEnrollView extends FrameLayout implements UdfpsEnrollHelper.Li
// Use parent view's and rotatedBound's absolute coordinates to decide the margins of
// UdfpsEnrollView, so that its center keeps consistent with sensor rect's.
ViewGroup parentView = (ViewGroup) getParent();
int[] coords = parentView.getLocationOnScreen();
int parentLeft = coords[0];
int parentTop = coords[1];
int parentRight = parentLeft + parentView.getWidth();
int parentBottom = parentTop + parentView.getHeight();
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) getLayoutParams();
FrameLayout.LayoutParams params = (LayoutParams) getLayoutParams();
switch (rotation) {
case Surface.ROTATION_0:
case Surface.ROTATION_180:
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
parentView.getViewTreeObserver().addOnDrawListener(() -> {
final int[] coords = parentView.getLocationOnScreen();
final int parentLeft = coords[0];
final int parentTop = coords[1];
final int parentRight = parentLeft + parentView.getWidth();
params.gravity = Gravity.RIGHT | Gravity.TOP;
marginLayoutParams.rightMargin = parentRight - rotatedBounds.right - getPaddingX();
marginLayoutParams.topMargin = rotatedBounds.top - parentTop - getPaddingY();
break;
case Surface.ROTATION_90:
final int rightMargin = parentRight - rotatedBounds.right - getPaddingX();
final int topMargin = rotatedBounds.top - parentTop - getPaddingY();
if (marginLayoutParams.rightMargin == rightMargin
&& marginLayoutParams.topMargin == topMargin) {
return;
}
marginLayoutParams.rightMargin = rightMargin;
marginLayoutParams.topMargin = topMargin;
setLayoutParams(params);
});
} else {
final int[] coords = parentView.getLocationOnScreen();
final int parentLeft = coords[0];
final int parentTop = coords[1];
final int parentRight = parentLeft + parentView.getWidth();
final int parentBottom = parentTop + parentView.getHeight();
if (rotation == Surface.ROTATION_90) {
params.gravity = Gravity.RIGHT | Gravity.BOTTOM;
marginLayoutParams.rightMargin = parentRight - rotatedBounds.right - getPaddingX();
marginLayoutParams.bottomMargin =
parentBottom - rotatedBounds.bottom - getPaddingY();
break;
case Surface.ROTATION_270:
} else if (rotation == Surface.ROTATION_270) {
params.gravity = Gravity.LEFT | Gravity.BOTTOM;
marginLayoutParams.leftMargin = rotatedBounds.left - parentLeft - getPaddingX();
marginLayoutParams.bottomMargin =
parentBottom - rotatedBounds.bottom - getPaddingY();
break;
}
}
params.height = rotatedBounds.height() + 2 * getPaddingX();

View File

@@ -17,9 +17,7 @@
package com.android.settings.display;
import android.content.Context;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
import android.util.Log;
import android.view.Display;
import androidx.annotation.VisibleForTesting;
@@ -27,63 +25,32 @@ import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/** Controller that switch the screen resolution. */
public class ScreenResolutionController extends BasePreferenceController {
private static final String TAG = "ScreenResolutionController";
static final int HIGHRESOLUTION_IDX = 0;
static final int FULLRESOLUTION_IDX = 1;
static final int FHD_WIDTH = 1080;
static final int QHD_WIDTH = 1440;
private Display mDisplay;
private Set<Point> mSupportedResolutions = null;
private int mHighWidth = 0;
private int mFullWidth = 0;
private int mHighHeight = 0;
private int mFullHeight = 0;
public ScreenResolutionController(Context context, String key) {
super(context, key);
mDisplay =
mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY);
initSupportedResolutionData();
}
/**
* Initialize the resolution data. So far, we support two resolution switching. Save the width
* and the height for high resolution and full resolution.
*/
private void initSupportedResolutionData() {
// Collect and filter the resolutions
Set<Point> resolutions = new HashSet<>();
/** Check if the width is supported by the display. */
private boolean isSupportedMode(int width) {
for (Display.Mode mode : getSupportedModes()) {
resolutions.add(new Point(mode.getPhysicalWidth(), mode.getPhysicalHeight()));
if (mode.getPhysicalWidth() == width) return true;
}
mSupportedResolutions = resolutions;
// Get the width and height for high resolution and full resolution
List<Point> resolutionList = new ArrayList<>(resolutions);
if (resolutionList == null || resolutionList.size() != 2) {
Log.e(TAG, "No support");
return;
}
Collections.sort(resolutionList, (p1, p2) -> p1.x * p1.y - p2.x * p2.y);
mHighWidth = resolutionList.get(HIGHRESOLUTION_IDX).x;
mHighHeight = resolutionList.get(HIGHRESOLUTION_IDX).y;
mFullWidth = resolutionList.get(FULLRESOLUTION_IDX).x;
mFullHeight = resolutionList.get(FULLRESOLUTION_IDX).y;
return false;
}
/** Return true if the device contains two (or more) resolutions. */
protected boolean checkSupportedResolutions() {
return getHighWidth() != 0 && getFullWidth() != 0;
return isSupportedMode(FHD_WIDTH) && isSupportedMode(QHD_WIDTH);
}
@Override
@@ -94,43 +61,20 @@ public class ScreenResolutionController extends BasePreferenceController {
@Override
public CharSequence getSummary() {
String summary = null;
int width = getDisplayWidth();
if (width == mHighWidth) {
summary = mContext.getString(R.string.screen_resolution_option_high);
} else if (width == mFullWidth) {
summary = mContext.getString(R.string.screen_resolution_option_full);
} else {
summary = mContext.getString(R.string.screen_resolution_title);
switch (getDisplayWidth()) {
case FHD_WIDTH:
summary = mContext.getString(R.string.screen_resolution_summary_high);
break;
case QHD_WIDTH:
summary = mContext.getString(R.string.screen_resolution_summary_highest);
break;
default:
summary = mContext.getString(R.string.screen_resolution_title);
}
return summary;
}
/** Return all supported resolutions of the device. */
public Set<Point> getAllSupportedResolutions() {
return this.mSupportedResolutions;
}
/** Return the high resolution width of the device. */
public int getHighWidth() {
return this.mHighWidth;
}
/** Return the full resolution width of the device. */
public int getFullWidth() {
return this.mFullWidth;
}
/** Return the high resolution height of the device. */
public int getHighHeight() {
return this.mHighHeight;
}
/** Return the full resolution height of the device. */
public int getFullHeight() {
return this.mFullHeight;
}
@VisibleForTesting
public int getDisplayWidth() {
return mDisplay.getMode().getPhysicalWidth();

View File

@@ -16,6 +16,9 @@
package com.android.settings.display;
import static com.android.settings.display.ScreenResolutionController.FHD_WIDTH;
import static com.android.settings.display.ScreenResolutionController.QHD_WIDTH;
import android.annotation.Nullable;
import android.app.settings.SettingsEnums;
import android.content.Context;
@@ -45,6 +48,7 @@ import com.android.settingslib.widget.IllustrationPreference;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
@@ -55,6 +59,8 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
private static final String TAG = "ScreenResolution";
private Resources mResources;
private static final int FHD_INDEX = 0;
private static final int QHD_INDEX = 1;
private static final String SCREEN_RESOLUTION = "user_selected_resolution";
private Display mDefaultDisplay;
private String[] mScreenResolutionOptions;
@@ -65,9 +71,6 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
private DisplayObserver mDisplayObserver;
private AccessibilityManager mAccessibilityManager;
private int mHighWidth;
private int mFullWidth;
@Override
public void onAttach(Context context) {
super.onAttach(context);
@@ -78,18 +81,11 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
mResources = context.getResources();
mScreenResolutionOptions =
mResources.getStringArray(R.array.config_screen_resolution_options_strings);
mScreenResolutionSummaries =
mResources.getStringArray(R.array.config_screen_resolution_summaries_strings);
mResolutions = getAllSupportedResolution();
mImagePreference = new IllustrationPreference(context);
mDisplayObserver = new DisplayObserver(context);
ScreenResolutionController mController =
new ScreenResolutionController(context, "fragment");
mResolutions = mController.getAllSupportedResolutions();
mHighWidth = mController.getHighWidth();
mFullWidth = mController.getFullWidth();
mScreenResolutionSummaries =
new String[] {
mHighWidth + " x " + mController.getHighHeight(),
mFullWidth + " x " + mController.getFullHeight()
};
}
@Override
@@ -137,6 +133,16 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
return candidates;
}
/** Get all supported resolutions on the device. */
private Set<Point> getAllSupportedResolution() {
Set<Point> resolutions = new HashSet<>();
for (Display.Mode mode : mDefaultDisplay.getSupportedModes()) {
resolutions.add(new Point(mode.getPhysicalWidth(), mode.getPhysicalHeight()));
}
return resolutions;
}
/** Get prefer display mode. */
private Display.Mode getPreferMode(int width) {
for (Point resolution : mResolutions) {
@@ -171,7 +177,6 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
try {
/** Apply the resolution change. */
Log.i(TAG, "setUserPreferredDisplayMode: " + mode);
mDefaultDisplay.setUserPreferredDisplayMode(mode);
} catch (Exception e) {
Log.e(TAG, "setUserPreferredDisplayMode() failed", e);
@@ -189,19 +194,16 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
/** Get the key corresponding to the resolution. */
@VisibleForTesting
String getKeyForResolution(int width) {
return width == mHighWidth
? mScreenResolutionOptions[ScreenResolutionController.HIGHRESOLUTION_IDX]
: width == mFullWidth
? mScreenResolutionOptions[ScreenResolutionController.FULLRESOLUTION_IDX]
: null;
return width == FHD_WIDTH
? mScreenResolutionOptions[FHD_INDEX]
: width == QHD_WIDTH ? mScreenResolutionOptions[QHD_INDEX] : null;
}
/** Get the width corresponding to the resolution key. */
int getWidthForResoluitonKey(String key) {
return mScreenResolutionOptions[ScreenResolutionController.HIGHRESOLUTION_IDX].equals(key)
? mHighWidth
: mScreenResolutionOptions[ScreenResolutionController.FULLRESOLUTION_IDX].equals(
key) ? mFullWidth : -1;
return mScreenResolutionOptions[FHD_INDEX].equals(key)
? FHD_WIDTH
: mScreenResolutionOptions[QHD_INDEX].equals(key) ? QHD_WIDTH : -1;
}
@Override
@@ -246,11 +248,9 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
private void updateIllustrationImage(IllustrationPreference preference) {
String key = getDefaultKey();
if (TextUtils.equals(
mScreenResolutionOptions[ScreenResolutionController.HIGHRESOLUTION_IDX], key)) {
if (TextUtils.equals(mScreenResolutionOptions[FHD_INDEX], key)) {
preference.setLottieAnimationResId(R.drawable.screen_resolution_1080p);
} else if (TextUtils.equals(
mScreenResolutionOptions[ScreenResolutionController.FULLRESOLUTION_IDX], key)) {
} else if (TextUtils.equals(mScreenResolutionOptions[QHD_INDEX], key)) {
preference.setLottieAnimationResId(R.drawable.screen_resolution_1440p);
}
}
@@ -408,8 +408,6 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
return false;
}
Log.i(TAG,
"resolution changed from " + mPreviousWidth.get() + " to " + getCurrentWidth());
return true;
}
}

View File

@@ -487,7 +487,7 @@ public class BatteryDiffEntry {
@Override
public Drawable getAppIcon() {
return mContext.getDrawable(R.drawable.ic_settings_ethernet);
return mContext.getDrawable(R.drawable.ic_settings_battery_usage_others);
}
@Override

View File

@@ -78,6 +78,7 @@ public class AppLocalePickerActivity extends SettingsBaseActivity
mContextAsUser,
this,
false /* translate only */,
null,
mPackageName,
this);
mAppLocaleDetails = AppLocaleDetails.newInstance(mPackageName, mContextAsUser.getUserId());

View File

@@ -318,6 +318,7 @@ public class LocaleListEditor extends RestrictedSettingsFragment {
final Intent intent = new Intent(getActivity(),
LocalePickerWithRegionActivity.class);
intent.putExtras(getActivity().getIntent().getExtras());
startActivityForResult(intent, REQUEST_LOCALE_PICKER);
}
});

View File

@@ -19,6 +19,9 @@ package com.android.settings.localepicker;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
import android.os.LocaleList;
import android.provider.Settings;
import android.util.Log;
import android.view.MenuItem;
import com.android.internal.app.LocalePickerWithRegion;
@@ -29,7 +32,7 @@ import com.android.settings.core.SettingsBaseActivity;
/** A activity to show the locale picker page. */
public class LocalePickerWithRegionActivity extends SettingsBaseActivity
implements LocalePickerWithRegion.LocaleSelectedListener {
private static final String TAG = LocalePickerWithRegionActivity.class.getSimpleName();
private static final String PARENT_FRAGMENT_NAME = "localeListEditor";
@Override
@@ -37,9 +40,20 @@ public class LocalePickerWithRegionActivity extends SettingsBaseActivity
super.onCreate(savedInstanceState);
getActionBar().setDisplayHomeAsUpEnabled(true);
setTitle(R.string.add_a_language);
LocaleList explicitLocales = null;
if (isDeviceDemoMode()) {
Bundle bundle = getIntent().getExtras();
explicitLocales = bundle == null
? null
: bundle.getParcelable(Settings.EXTRA_EXPLICIT_LOCALES, LocaleList.class);
Log.i(TAG, "Has explicit locales : " + explicitLocales);
}
final LocalePickerWithRegion selector = LocalePickerWithRegion.createLanguagePicker(
this, LocalePickerWithRegionActivity.this, false /* translate only */);
this,
LocalePickerWithRegionActivity.this,
false /* translate only */,
explicitLocales);
getFragmentManager()
.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
@@ -78,5 +92,10 @@ public class LocalePickerWithRegionActivity extends SettingsBaseActivity
finish();
}
}
private boolean isDeviceDemoMode() {
return Settings.Global.getInt(
getContentResolver(), Settings.Global.DEVICE_DEMO_MODE, 0) == 1;
}
}

View File

@@ -0,0 +1,178 @@
/*
* 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.spa.app.specialaccess
import android.app.AppOpsManager
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.PackageInfoFlags
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
import com.android.settingslib.spaprivileged.model.app.AppOpsController
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.eq
import org.mockito.Spy
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
import org.mockito.Mockito.`when` as whenever
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class PictureInPictureTest {
@get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
@Spy
private val context: Context = ApplicationProvider.getApplicationContext()
@Mock
private lateinit var packageManager: PackageManager
private lateinit var listModel: PictureInPictureListModel
@Before
fun setUp() {
whenever(context.packageManager).thenReturn(packageManager)
whenever(packageManager.getInstalledPackagesAsUser(any<PackageInfoFlags>(), anyInt()))
.thenReturn(emptyList())
listModel = PictureInPictureListModel(context)
}
@Test
fun pageTitleResId() {
assertThat(listModel.pageTitleResId).isEqualTo(R.string.picture_in_picture_title)
}
@Test
fun switchTitleResId() {
assertThat(listModel.switchTitleResId)
.isEqualTo(R.string.picture_in_picture_app_detail_switch)
}
@Test
fun footerResId() {
assertThat(listModel.footerResId).isEqualTo(R.string.picture_in_picture_app_detail_summary)
}
@Test
fun transform() = runTest {
whenever(packageManager.getInstalledPackagesAsUser(any<PackageInfoFlags>(), anyInt()))
.thenReturn(listOf(PICTURE_IN_PICTURE_PACKAGE_INFO))
val recordListFlow = listModel.transform(
userIdFlow = flowOf(USER_ID),
appListFlow = flowOf(listOf(PICTURE_IN_PICTURE_APP)),
)
val recordList = recordListFlow.first()
assertThat(recordList).hasSize(1)
val record = recordList[0]
assertThat(record.app).isSameInstanceAs(PICTURE_IN_PICTURE_APP)
assertThat(record.isSupport).isTrue()
}
@Test
fun transformItem() {
whenever(
packageManager.getPackageInfoAsUser(
eq(PICTURE_IN_PICTURE_PACKAGE_NAME), any<PackageInfoFlags>(), eq(USER_ID)
)
).thenReturn(PICTURE_IN_PICTURE_PACKAGE_INFO)
val record = listModel.transformItem(PICTURE_IN_PICTURE_APP)
assertThat(record.app).isSameInstanceAs(PICTURE_IN_PICTURE_APP)
assertThat(record.isSupport).isTrue()
}
@Test
fun filter_isSupport() = runTest {
val record = createRecord(isSupport = true)
val recordListFlow = listModel.filter(flowOf(USER_ID), flowOf(listOf(record)))
val recordList = recordListFlow.first()
assertThat(recordList).hasSize(1)
}
@Test
fun filter_notSupport() = runTest {
val record = createRecord(isSupport = false)
val recordListFlow = listModel.filter(flowOf(USER_ID), flowOf(listOf(record)))
val recordList = recordListFlow.first()
assertThat(recordList).isEmpty()
}
@Test
fun isChangeable_isSupport() {
val record = createRecord(isSupport = true)
val isChangeable = listModel.isChangeable(record)
assertThat(isChangeable).isTrue()
}
@Test
fun isChangeable_notSupport() {
val record = createRecord(isSupport = false)
val isChangeable = listModel.isChangeable(record)
assertThat(isChangeable).isFalse()
}
private fun createRecord(isSupport: Boolean) = PictureInPictureRecord(
app = PICTURE_IN_PICTURE_APP,
isSupport = isSupport,
appOpsController = AppOpsController(
context = context,
app = PICTURE_IN_PICTURE_APP,
op = AppOpsManager.OP_PICTURE_IN_PICTURE,
),
)
private companion object {
const val USER_ID = 0
const val PICTURE_IN_PICTURE_PACKAGE_NAME = "picture.in.picture.package.name"
val PICTURE_IN_PICTURE_APP = ApplicationInfo().apply {
packageName = PICTURE_IN_PICTURE_PACKAGE_NAME
}
val PICTURE_IN_PICTURE_PACKAGE_INFO = PackageInfo().apply {
packageName = PICTURE_IN_PICTURE_PACKAGE_NAME
activities = arrayOf(ActivityInfo().apply {
flags = ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE
})
}
}
}