Snap for 9839270 from 25665fe672 to udc-release
Change-Id: I8767f37ab4edb0a683f9cdcfc81e4a3fc29e42e4
This commit is contained in:
@@ -80,7 +80,7 @@
|
|||||||
android:drawablePadding="9dp"
|
android:drawablePadding="9dp"
|
||||||
style="@style/ModifierKeyButtonCancel"
|
style="@style/ModifierKeyButtonCancel"
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:text="@string/modifier_keys_restore"/>
|
android:text="@string/modifier_keys_reset"/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -67,5 +67,9 @@
|
|||||||
<color name="udfps_enroll_progress">#7DA7F1</color>
|
<color name="udfps_enroll_progress">#7DA7F1</color>
|
||||||
<color name="udfps_enroll_progress_help">#607DA7F1</color>
|
<color name="udfps_enroll_progress_help">#607DA7F1</color>
|
||||||
<color name="udfps_enroll_progress_help_with_talkback">#FFEE675C</color>
|
<color name="udfps_enroll_progress_help_with_talkback">#FFEE675C</color>
|
||||||
|
|
||||||
|
<!-- Flash notifications colors -->
|
||||||
|
<!-- Screen flash notification color selected stroke in color selection dialog -->
|
||||||
|
<color name="screen_flash_color_button_outer_circle_stroke_color">#FFFFFF</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
|
|||||||
@@ -4008,7 +4008,7 @@
|
|||||||
<!-- Text of the cancel button. [CHAR LIMIT=15] -->
|
<!-- Text of the cancel button. [CHAR LIMIT=15] -->
|
||||||
<string name="modifier_keys_cancel">Cancel</string>
|
<string name="modifier_keys_cancel">Cancel</string>
|
||||||
<!-- Text of the restore button. [CHAR LIMIT=15] -->
|
<!-- Text of the restore button. [CHAR LIMIT=15] -->
|
||||||
<string name="modifier_keys_restore">Restore</string>
|
<string name="modifier_keys_reset">Reset</string>
|
||||||
<!-- Title for the modifier key picker dialog page [CHAR LIMIT=35] -->
|
<!-- Title for the modifier key picker dialog page [CHAR LIMIT=35] -->
|
||||||
<string name="modifier_keys_picker_title">Choose modifier key</string>
|
<string name="modifier_keys_picker_title">Choose modifier key</string>
|
||||||
<!-- Summary for the modifier key picker dialog page [CHAR LIMIT=35] -->
|
<!-- Summary for the modifier key picker dialog page [CHAR LIMIT=35] -->
|
||||||
@@ -4595,6 +4595,8 @@
|
|||||||
<string name="accessibility_one_handed_mode_auto_added_qs_tooltip_content">One-handed mode added to Quick Settings. Swipe down to turn it on or off anytime.</string>
|
<string name="accessibility_one_handed_mode_auto_added_qs_tooltip_content">One-handed mode added to Quick Settings. Swipe down to turn it on or off anytime.</string>
|
||||||
<!-- Used in the One-hand mode settings to show quick settings tooltip. [CHAR LIMIT=NONE] -->
|
<!-- Used in the One-hand mode settings to show quick settings tooltip. [CHAR LIMIT=NONE] -->
|
||||||
<string name="accessibility_one_handed_mode_qs_tooltip_content">You can also add one-handed mode to Quick Settings from the top of your screen</string>
|
<string name="accessibility_one_handed_mode_qs_tooltip_content">You can also add one-handed mode to Quick Settings from the top of your screen</string>
|
||||||
|
<!-- Used in the font size settings to show quick settings tooltip for auto-added feature. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="accessibility_font_scaling_auto_added_qs_tooltip_content">Font size added to Quick Settings. Swipe down to change the font size anytime.</string>
|
||||||
<!-- Used in the accessibility action for accessibility quick settings tooltip to dismiss. [CHAR LIMIT=NONE] -->
|
<!-- Used in the accessibility action for accessibility quick settings tooltip to dismiss. [CHAR LIMIT=NONE] -->
|
||||||
<string name="accessibility_quick_settings_tooltip_dismiss">Dismiss</string>
|
<string name="accessibility_quick_settings_tooltip_dismiss">Dismiss</string>
|
||||||
<!-- Used in the Color correction settings screen to control turning on/off the feature entirely [CHAR LIMIT=60] -->
|
<!-- Used in the Color correction settings screen to control turning on/off the feature entirely [CHAR LIMIT=60] -->
|
||||||
@@ -11970,6 +11972,8 @@
|
|||||||
<string name="flash_notifications_summary_on_camera_and_screen">On / Camera and screen flash</string>
|
<string name="flash_notifications_summary_on_camera_and_screen">On / Camera and screen flash</string>
|
||||||
<!-- Introduction in Flash Notification page to introduce flash notifications feature. [CHAR LIMIT=NONE] -->
|
<!-- Introduction in Flash Notification page to introduce flash notifications feature. [CHAR LIMIT=NONE] -->
|
||||||
<string name="flash_notifications_intro">Flash the camera light or the screen when you receive notifications or when alarms sound</string>
|
<string name="flash_notifications_intro">Flash the camera light or the screen when you receive notifications or when alarms sound</string>
|
||||||
|
<!-- Introduction in Flash Notification page to introduce flash notifications feature without camera flash option. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="flash_notifications_intro_without_camera_flash">Flash the screen when you receive notifications or when alarms sound</string>
|
||||||
<!-- Notes in Flash Notification page footer for something should be aware. [CHAR LIMIT=NONE] -->
|
<!-- Notes in Flash Notification page footer for something should be aware. [CHAR LIMIT=NONE] -->
|
||||||
<string name="flash_notifications_note">Use flash notifications with caution if you\u0027re light sensitive</string>
|
<string name="flash_notifications_note">Use flash notifications with caution if you\u0027re light sensitive</string>
|
||||||
<!-- Label of the button to preview the selected Flash Notification effects. [CHAR LIMIT=20]-->
|
<!-- Label of the button to preview the selected Flash Notification effects. [CHAR LIMIT=20]-->
|
||||||
|
|||||||
@@ -21,12 +21,12 @@
|
|||||||
|
|
||||||
<com.android.settingslib.widget.TopIntroPreference
|
<com.android.settingslib.widget.TopIntroPreference
|
||||||
android:key="flash_notifications_intro"
|
android:key="flash_notifications_intro"
|
||||||
android:title="@string/flash_notifications_intro" />
|
settings:controller="com.android.settings.accessibility.FlashNotificationsIntroPreferenceController" />
|
||||||
|
|
||||||
<com.android.settingslib.widget.IllustrationPreference
|
<com.android.settingslib.widget.IllustrationPreference
|
||||||
android:key="flash_notifications_illustration"
|
android:key="flash_notifications_illustration"
|
||||||
settings:searchable="false"
|
settings:searchable="false"
|
||||||
settings:lottie_rawRes="@drawable/flash_notifications_illustration"/>
|
settings:lottie_rawRes="@drawable/flash_notifications_illustration" />
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:key="camera_flash_notification_preference"
|
android:key="camera_flash_notification_preference"
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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.accessibility;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
|
||||||
|
/** Preference controller that controls the text content of Flash Notifications intro. */
|
||||||
|
public class FlashNotificationsIntroPreferenceController extends BasePreferenceController {
|
||||||
|
|
||||||
|
public FlashNotificationsIntroPreferenceController(Context context,
|
||||||
|
String preferenceKey) {
|
||||||
|
super(context, preferenceKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAvailabilityStatus() {
|
||||||
|
return AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
super.displayPreference(screen);
|
||||||
|
final int titleResource = FlashNotificationsUtil.isTorchAvailable(mContext)
|
||||||
|
? R.string.flash_notifications_intro
|
||||||
|
: R.string.flash_notifications_intro_without_camera_flash;
|
||||||
|
final Preference preference = screen.findPreference(getPreferenceKey());
|
||||||
|
if (preference != null) {
|
||||||
|
preference.setTitle(titleResource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,14 +16,22 @@
|
|||||||
|
|
||||||
package com.android.settings.accessibility;
|
package com.android.settings.accessibility;
|
||||||
|
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
import com.android.settings.core.BasePreferenceController;
|
import com.android.settings.core.BasePreferenceController;
|
||||||
import com.android.settings.widget.LabeledSeekBarPreference;
|
import com.android.settings.widget.LabeledSeekBarPreference;
|
||||||
|
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||||
|
import com.android.settingslib.core.lifecycle.events.OnCreate;
|
||||||
|
import com.android.settingslib.core.lifecycle.events.OnDestroy;
|
||||||
|
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@@ -31,12 +39,19 @@ import java.util.Optional;
|
|||||||
* The controller of {@link LabeledSeekBarPreference} that listens to display size and font size
|
* The controller of {@link LabeledSeekBarPreference} that listens to display size and font size
|
||||||
* settings changes and updates preview size threshold smoothly.
|
* settings changes and updates preview size threshold smoothly.
|
||||||
*/
|
*/
|
||||||
class PreviewSizeSeekBarController extends BasePreferenceController implements
|
abstract class PreviewSizeSeekBarController extends BasePreferenceController implements
|
||||||
TextReadingResetController.ResetStateListener {
|
TextReadingResetController.ResetStateListener, LifecycleObserver, OnCreate,
|
||||||
|
OnDestroy, OnSaveInstanceState {
|
||||||
private final PreviewSizeData<? extends Number> mSizeData;
|
private final PreviewSizeData<? extends Number> mSizeData;
|
||||||
|
private static final String KEY_SAVED_QS_TOOLTIP_RESHOW = "qs_tooltip_reshow";
|
||||||
private boolean mSeekByTouch;
|
private boolean mSeekByTouch;
|
||||||
private Optional<ProgressInteractionListener> mInteractionListener = Optional.empty();
|
private Optional<ProgressInteractionListener> mInteractionListener = Optional.empty();
|
||||||
private LabeledSeekBarPreference mSeekBarPreference;
|
private LabeledSeekBarPreference mSeekBarPreference;
|
||||||
|
private int mLastProgress;
|
||||||
|
private boolean mNeedsQSTooltipReshow = false;
|
||||||
|
private AccessibilityQuickSettingsTooltipWindow mTooltipWindow;
|
||||||
|
private final Handler mHandler;
|
||||||
|
|
||||||
|
|
||||||
private final SeekBar.OnSeekBarChangeListener mSeekBarChangeListener =
|
private final SeekBar.OnSeekBarChangeListener mSeekBarChangeListener =
|
||||||
new SeekBar.OnSeekBarChangeListener() {
|
new SeekBar.OnSeekBarChangeListener() {
|
||||||
@@ -54,6 +69,7 @@ class PreviewSizeSeekBarController extends BasePreferenceController implements
|
|||||||
|
|
||||||
if (!mSeekByTouch) {
|
if (!mSeekByTouch) {
|
||||||
interactionListener.onProgressChanged();
|
interactionListener.onProgressChanged();
|
||||||
|
onProgressFinalized();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +83,7 @@ class PreviewSizeSeekBarController extends BasePreferenceController implements
|
|||||||
mSeekByTouch = false;
|
mSeekByTouch = false;
|
||||||
|
|
||||||
mInteractionListener.ifPresent(ProgressInteractionListener::onEndTrackingTouch);
|
mInteractionListener.ifPresent(ProgressInteractionListener::onEndTrackingTouch);
|
||||||
|
onProgressFinalized();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -74,6 +91,30 @@ class PreviewSizeSeekBarController extends BasePreferenceController implements
|
|||||||
@NonNull PreviewSizeData<? extends Number> sizeData) {
|
@NonNull PreviewSizeData<? extends Number> sizeData) {
|
||||||
super(context, preferenceKey);
|
super(context, preferenceKey);
|
||||||
mSizeData = sizeData;
|
mSizeData = sizeData;
|
||||||
|
mHandler = new Handler(context.getMainLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
// Restore the tooltip.
|
||||||
|
if (savedInstanceState != null
|
||||||
|
&& savedInstanceState.containsKey(KEY_SAVED_QS_TOOLTIP_RESHOW)) {
|
||||||
|
mNeedsQSTooltipReshow = savedInstanceState.getBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
// remove runnables in the queue.
|
||||||
|
mHandler.removeCallbacksAndMessages(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
|
final boolean isTooltipWindowShowing = mTooltipWindow != null && mTooltipWindow.isShowing();
|
||||||
|
if (mNeedsQSTooltipReshow || isTooltipWindowShowing) {
|
||||||
|
outState.putBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW, /* value= */ true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setInteractionListener(ProgressInteractionListener interactionListener) {
|
void setInteractionListener(ProgressInteractionListener interactionListener) {
|
||||||
@@ -91,11 +132,15 @@ class PreviewSizeSeekBarController extends BasePreferenceController implements
|
|||||||
|
|
||||||
final int dataSize = mSizeData.getValues().size();
|
final int dataSize = mSizeData.getValues().size();
|
||||||
final int initialIndex = mSizeData.getInitialIndex();
|
final int initialIndex = mSizeData.getInitialIndex();
|
||||||
|
mLastProgress = initialIndex;
|
||||||
mSeekBarPreference = screen.findPreference(getPreferenceKey());
|
mSeekBarPreference = screen.findPreference(getPreferenceKey());
|
||||||
mSeekBarPreference.setMax(dataSize - 1);
|
mSeekBarPreference.setMax(dataSize - 1);
|
||||||
mSeekBarPreference.setProgress(initialIndex);
|
mSeekBarPreference.setProgress(initialIndex);
|
||||||
mSeekBarPreference.setContinuousUpdates(true);
|
mSeekBarPreference.setContinuousUpdates(true);
|
||||||
mSeekBarPreference.setOnSeekBarChangeListener(mSeekBarChangeListener);
|
mSeekBarPreference.setOnSeekBarChangeListener(mSeekBarChangeListener);
|
||||||
|
if (mNeedsQSTooltipReshow) {
|
||||||
|
mHandler.post(this::showQuickSettingsTooltipIfNeeded);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -108,6 +153,44 @@ class PreviewSizeSeekBarController extends BasePreferenceController implements
|
|||||||
mInteractionListener.ifPresent(ProgressInteractionListener::onProgressChanged);
|
mInteractionListener.ifPresent(ProgressInteractionListener::onProgressChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onProgressFinalized() {
|
||||||
|
// Using progress in SeekBarPreference since the progresses in
|
||||||
|
// SeekBarPreference and seekbar are not always the same.
|
||||||
|
// See {@link androidx.preference.Preference#callChangeListener(Object)}
|
||||||
|
int seekBarPreferenceProgress = mSeekBarPreference.getProgress();
|
||||||
|
if (seekBarPreferenceProgress != mLastProgress) {
|
||||||
|
showQuickSettingsTooltipIfNeeded();
|
||||||
|
mLastProgress = seekBarPreferenceProgress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showQuickSettingsTooltipIfNeeded() {
|
||||||
|
final ComponentName tileComponentName = getTileComponentName();
|
||||||
|
if (tileComponentName == null) {
|
||||||
|
// Returns if no tile service assigned.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mNeedsQSTooltipReshow && AccessibilityQuickSettingUtils.hasValueInSharedPreferences(
|
||||||
|
mContext, tileComponentName)) {
|
||||||
|
// Returns if quick settings tooltip only show once.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTooltipWindow = new AccessibilityQuickSettingsTooltipWindow(mContext);
|
||||||
|
mTooltipWindow.setup(getTileTooltipContent(),
|
||||||
|
R.drawable.accessibility_auto_added_qs_tooltip_illustration);
|
||||||
|
mTooltipWindow.showAtTopCenter(mSeekBarPreference.getSeekbar());
|
||||||
|
AccessibilityQuickSettingUtils.optInValueToSharedPreferences(mContext, tileComponentName);
|
||||||
|
mNeedsQSTooltipReshow = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the accessibility Quick Settings tile component name. */
|
||||||
|
abstract ComponentName getTileComponentName();
|
||||||
|
|
||||||
|
/** Returns accessibility Quick Settings tile tooltip content. */
|
||||||
|
abstract CharSequence getTileTooltipContent();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for callbacks when users interact with the seek bar.
|
* Interface for callbacks when users interact with the seek bar.
|
||||||
|
|||||||
@@ -16,11 +16,13 @@
|
|||||||
|
|
||||||
package com.android.settings.accessibility;
|
package com.android.settings.accessibility;
|
||||||
|
|
||||||
|
import static com.android.internal.accessibility.AccessibilityShortcutController.FONT_SIZE_COMPONENT_NAME;
|
||||||
import static com.android.settings.accessibility.TextReadingResetController.ResetStateListener;
|
import static com.android.settings.accessibility.TextReadingResetController.ResetStateListener;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -156,12 +158,34 @@ public class TextReadingPreferenceFragment extends DashboardFragment {
|
|||||||
controllers.add(mPreviewController);
|
controllers.add(mPreviewController);
|
||||||
|
|
||||||
final PreviewSizeSeekBarController fontSizeController = new PreviewSizeSeekBarController(
|
final PreviewSizeSeekBarController fontSizeController = new PreviewSizeSeekBarController(
|
||||||
context, FONT_SIZE_KEY, fontSizeData);
|
context, FONT_SIZE_KEY, fontSizeData) {
|
||||||
|
@Override
|
||||||
|
ComponentName getTileComponentName() {
|
||||||
|
return FONT_SIZE_COMPONENT_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
CharSequence getTileTooltipContent() {
|
||||||
|
return context.getText(
|
||||||
|
R.string.accessibility_font_scaling_auto_added_qs_tooltip_content);
|
||||||
|
}
|
||||||
|
};
|
||||||
fontSizeController.setInteractionListener(mPreviewController);
|
fontSizeController.setInteractionListener(mPreviewController);
|
||||||
|
getSettingsLifecycle().addObserver(fontSizeController);
|
||||||
controllers.add(fontSizeController);
|
controllers.add(fontSizeController);
|
||||||
|
|
||||||
final PreviewSizeSeekBarController displaySizeController = new PreviewSizeSeekBarController(
|
final PreviewSizeSeekBarController displaySizeController = new PreviewSizeSeekBarController(
|
||||||
context, DISPLAY_SIZE_KEY, displaySizeData);
|
context, DISPLAY_SIZE_KEY, displaySizeData) {
|
||||||
|
@Override
|
||||||
|
ComponentName getTileComponentName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
CharSequence getTileTooltipContent() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
displaySizeController.setInteractionListener(mPreviewController);
|
displaySizeController.setInteractionListener(mPreviewController);
|
||||||
controllers.add(displaySizeController);
|
controllers.add(displaySizeController);
|
||||||
|
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ public class AppLocaleDetails extends SettingsPreferenceFragment {
|
|||||||
if (appLocale == null) {
|
if (appLocale == null) {
|
||||||
return context.getString(R.string.preference_of_system_locale_summary);
|
return context.getString(R.string.preference_of_system_locale_summary);
|
||||||
} else {
|
} else {
|
||||||
return LocaleHelper.getDisplayName(appLocale, appLocale, true);
|
return LocaleHelper.getDisplayName(appLocale.stripExtensions(), appLocale, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -452,6 +452,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
|||||||
item.registerCallback(this);
|
item.registerCallback(this);
|
||||||
}
|
}
|
||||||
mProfileManager.addServiceListener(this);
|
mProfileManager.addServiceListener(this);
|
||||||
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -251,10 +251,10 @@ public class ScreenResolutionFragment extends RadioButtonPickerFragment {
|
|||||||
|
|
||||||
if (TextUtils.equals(
|
if (TextUtils.equals(
|
||||||
mScreenResolutionOptions[ScreenResolutionController.HIGHRESOLUTION_IDX], key)) {
|
mScreenResolutionOptions[ScreenResolutionController.HIGHRESOLUTION_IDX], key)) {
|
||||||
preference.setLottieAnimationResId(R.drawable.screen_resolution_1080p);
|
preference.setLottieAnimationResId(R.drawable.screen_resolution_high);
|
||||||
} else if (TextUtils.equals(
|
} else if (TextUtils.equals(
|
||||||
mScreenResolutionOptions[ScreenResolutionController.FULLRESOLUTION_IDX], key)) {
|
mScreenResolutionOptions[ScreenResolutionController.FULLRESOLUTION_IDX], key)) {
|
||||||
preference.setLottieAnimationResId(R.drawable.screen_resolution_1440p);
|
preference.setLottieAnimationResId(R.drawable.screen_resolution_full);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,11 +29,12 @@ import android.content.ComponentName;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.PackageManager.ApplicationInfoFlags;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -71,7 +72,6 @@ import com.android.settings.core.CategoryMixin;
|
|||||||
import com.android.settings.core.FeatureFlags;
|
import com.android.settings.core.FeatureFlags;
|
||||||
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
|
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settings.password.PasswordUtils;
|
|
||||||
import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
|
import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
|
||||||
import com.android.settingslib.Utils;
|
import com.android.settingslib.Utils;
|
||||||
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
|
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
|
||||||
@@ -96,6 +96,10 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
|||||||
public static final String EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_DATA =
|
public static final String EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_DATA =
|
||||||
"settings_large_screen_deep_link_intent_data";
|
"settings_large_screen_deep_link_intent_data";
|
||||||
|
|
||||||
|
// The referrer who fires the initial intent to start the homepage
|
||||||
|
@VisibleForTesting
|
||||||
|
static final String EXTRA_INITIAL_REFERRER = "initial_referrer";
|
||||||
|
|
||||||
static final int DEFAULT_HIGHLIGHT_MENU_KEY = R.string.menu_key_network;
|
static final int DEFAULT_HIGHLIGHT_MENU_KEY = R.string.menu_key_network;
|
||||||
private static final long HOMEPAGE_LOADING_TIMEOUT_MS = 300;
|
private static final long HOMEPAGE_LOADING_TIMEOUT_MS = 300;
|
||||||
|
|
||||||
@@ -177,12 +181,16 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
|||||||
mIsEmbeddingActivityEnabled = ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this);
|
mIsEmbeddingActivityEnabled = ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this);
|
||||||
if (mIsEmbeddingActivityEnabled) {
|
if (mIsEmbeddingActivityEnabled) {
|
||||||
final UserManager um = getSystemService(UserManager.class);
|
final UserManager um = getSystemService(UserManager.class);
|
||||||
final UserInfo userInfo = um.getUserInfo(getUser().getIdentifier());
|
final UserInfo userInfo = um.getUserInfo(getUserId());
|
||||||
if (userInfo.isManagedProfile()) {
|
if (userInfo.isManagedProfile()) {
|
||||||
final Intent intent = new Intent(getIntent())
|
final Intent intent = new Intent(getIntent())
|
||||||
.setClass(this, DeepLinkHomepageActivityInternal.class)
|
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
|
.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
|
||||||
.putExtra(EXTRA_USER_HANDLE, getUser());
|
.putExtra(EXTRA_USER_HANDLE, getUser())
|
||||||
|
.putExtra(EXTRA_INITIAL_REFERRER, getCurrentReferrer());
|
||||||
|
if (TextUtils.equals(intent.getAction(), ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY)
|
||||||
|
&& this instanceof DeepLinkHomepageActivity) {
|
||||||
|
intent.setClass(this, DeepLinkHomepageActivityInternal.class);
|
||||||
|
}
|
||||||
intent.removeFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.removeFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
startActivityAsUser(intent, um.getProfileParent(userInfo.id).getUserHandle());
|
startActivityAsUser(intent, um.getProfileParent(userInfo.id).getUserHandle());
|
||||||
finish();
|
finish();
|
||||||
@@ -471,7 +479,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ActivityInfo targetActivityInfo = null;
|
ActivityInfo targetActivityInfo;
|
||||||
try {
|
try {
|
||||||
targetActivityInfo = getPackageManager().getActivityInfo(targetComponentName,
|
targetActivityInfo = getPackageManager().getActivityInfo(targetComponentName,
|
||||||
/* flags= */ 0);
|
/* flags= */ 0);
|
||||||
@@ -481,23 +489,29 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int callingUid = -1;
|
UserHandle user = intent.getParcelableExtra(EXTRA_USER_HANDLE, UserHandle.class);
|
||||||
|
String caller = getInitialReferrer();
|
||||||
|
int callerUid = -1;
|
||||||
|
if (caller != null) {
|
||||||
try {
|
try {
|
||||||
callingUid = ActivityManager.getService().getLaunchedFromUid(getActivityToken());
|
callerUid = getPackageManager().getApplicationInfoAsUser(caller,
|
||||||
} catch (RemoteException re) {
|
ApplicationInfoFlags.of(/* flags= */ 0),
|
||||||
Log.e(TAG, "Not able to get callingUid: " + re);
|
user != null ? user.getIdentifier() : getUserId()).uid;
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
Log.e(TAG, "Not able to get callerUid: " + e);
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!hasPrivilegedAccess(callingUid, targetActivityInfo)) {
|
if (!hasPrivilegedAccess(caller, callerUid, targetActivityInfo.packageName)) {
|
||||||
if (!targetActivityInfo.exported) {
|
if (!targetActivityInfo.exported) {
|
||||||
Log.e(TAG, "Target Activity is not exported");
|
Log.e(TAG, "Target Activity is not exported");
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isCallingAppPermitted(targetActivityInfo.permission)) {
|
if (!isCallingAppPermitted(targetActivityInfo.permission, callerUid)) {
|
||||||
Log.e(TAG, "Calling app must have the permission of deep link Activity");
|
Log.e(TAG, "Calling app must have the permission of deep link Activity");
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
@@ -510,7 +524,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
|||||||
& (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
& (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||||
if (targetIntent.getData() != null
|
if (targetIntent.getData() != null
|
||||||
&& uriPermissionFlags != 0
|
&& uriPermissionFlags != 0
|
||||||
&& checkUriPermission(targetIntent.getData(), /* pid= */ -1, callingUid,
|
&& checkUriPermission(targetIntent.getData(), /* pid= */ -1, callerUid,
|
||||||
uriPermissionFlags) == PackageManager.PERMISSION_DENIED) {
|
uriPermissionFlags) == PackageManager.PERMISSION_DENIED) {
|
||||||
Log.e(TAG, "Calling app must have the permission to access Uri and grant permission");
|
Log.e(TAG, "Calling app must have the permission to access Uri and grant permission");
|
||||||
finish();
|
finish();
|
||||||
@@ -547,7 +561,6 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
|||||||
SplitRule.FinishBehavior.ALWAYS,
|
SplitRule.FinishBehavior.ALWAYS,
|
||||||
true /* clearTop */);
|
true /* clearTop */);
|
||||||
|
|
||||||
final UserHandle user = intent.getParcelableExtra(EXTRA_USER_HANDLE, UserHandle.class);
|
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
startActivityAsUser(targetIntent, user);
|
startActivityAsUser(targetIntent, user);
|
||||||
} else {
|
} else {
|
||||||
@@ -555,31 +568,30 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if calling app has privileged access to launch Activity of activityInfo.
|
// Check if the caller has privileged access to launch the target page.
|
||||||
private boolean hasPrivilegedAccess(int callingUid, ActivityInfo activityInfo) {
|
private boolean hasPrivilegedAccess(String callerPkg, int callerUid, String targetPackage) {
|
||||||
if (TextUtils.equals(PasswordUtils.getCallingAppPackageName(getActivityToken()),
|
if (TextUtils.equals(callerPkg, getPackageName())) {
|
||||||
getPackageName())) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int targetUid = -1;
|
int targetUid = -1;
|
||||||
try {
|
try {
|
||||||
targetUid = getPackageManager().getApplicationInfo(activityInfo.packageName,
|
targetUid = getPackageManager().getApplicationInfo(targetPackage,
|
||||||
/* flags= */ 0).uid;
|
ApplicationInfoFlags.of(/* flags= */ 0)).uid;
|
||||||
} catch (PackageManager.NameNotFoundException nnfe) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
Log.e(TAG, "Not able to get targetUid: " + nnfe);
|
Log.e(TAG, "Not able to get targetUid: " + e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When activityInfo.exported is false, Activity still can be launched if applications have
|
// When activityInfo.exported is false, Activity still can be launched if applications have
|
||||||
// the same user ID.
|
// the same user ID.
|
||||||
if (UserHandle.isSameApp(callingUid, targetUid)) {
|
if (UserHandle.isSameApp(callerUid, targetUid)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When activityInfo.exported is false, Activity still can be launched if calling app has
|
// When activityInfo.exported is false, Activity still can be launched if calling app has
|
||||||
// root or system privilege.
|
// root or system privilege.
|
||||||
int callingAppId = UserHandle.getAppId(callingUid);
|
int callingAppId = UserHandle.getAppId(callerUid);
|
||||||
if (callingAppId == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID) {
|
if (callingAppId == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -588,9 +600,31 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
boolean isCallingAppPermitted(String permission) {
|
String getInitialReferrer() {
|
||||||
return TextUtils.isEmpty(permission) || PasswordUtils.isCallingAppPermitted(
|
String referrer = getCurrentReferrer();
|
||||||
this, getActivityToken(), permission);
|
if (!TextUtils.equals(referrer, getPackageName())) {
|
||||||
|
return referrer;
|
||||||
|
}
|
||||||
|
|
||||||
|
String initialReferrer = getIntent().getStringExtra(EXTRA_INITIAL_REFERRER);
|
||||||
|
return TextUtils.isEmpty(initialReferrer) ? referrer : initialReferrer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
String getCurrentReferrer() {
|
||||||
|
Intent intent = getIntent();
|
||||||
|
// Clear extras to get the real referrer
|
||||||
|
intent.removeExtra(Intent.EXTRA_REFERRER);
|
||||||
|
intent.removeExtra(Intent.EXTRA_REFERRER_NAME);
|
||||||
|
Uri referrer = getReferrer();
|
||||||
|
return referrer != null ? referrer.getHost() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean isCallingAppPermitted(String permission, int callerUid) {
|
||||||
|
return TextUtils.isEmpty(permission)
|
||||||
|
|| checkPermission(permission, /* pid= */ -1, callerUid)
|
||||||
|
== PackageManager.PERMISSION_GRANTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getHighlightMenuKey() {
|
private String getHighlightMenuKey() {
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ public class LabeledSeekBarPreference extends SeekBarPreference {
|
|||||||
private OnPreferenceChangeListener mStopListener;
|
private OnPreferenceChangeListener mStopListener;
|
||||||
private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener;
|
private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener;
|
||||||
|
|
||||||
|
private SeekBar mSeekBar;
|
||||||
|
|
||||||
public LabeledSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr,
|
public LabeledSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr,
|
||||||
int defStyleRes) {
|
int defStyleRes) {
|
||||||
|
|
||||||
@@ -104,6 +106,10 @@ public class LabeledSeekBarPreference extends SeekBarPreference {
|
|||||||
com.android.internal.R.attr.seekBarPreferenceStyle), 0);
|
com.android.internal.R.attr.seekBarPreferenceStyle), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SeekBar getSeekbar() {
|
||||||
|
return mSeekBar;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||||
super.onBindViewHolder(holder);
|
super.onBindViewHolder(holder);
|
||||||
@@ -133,19 +139,19 @@ public class LabeledSeekBarPreference extends SeekBarPreference {
|
|||||||
final boolean isValidTextResIdExist = mTextStartId > 0 || mTextEndId > 0;
|
final boolean isValidTextResIdExist = mTextStartId > 0 || mTextEndId > 0;
|
||||||
labelFrame.setVisibility(isValidTextResIdExist ? View.VISIBLE : View.GONE);
|
labelFrame.setVisibility(isValidTextResIdExist ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
final SeekBar seekBar = (SeekBar) holder.findViewById(com.android.internal.R.id.seekbar);
|
mSeekBar = (SeekBar) holder.findViewById(com.android.internal.R.id.seekbar);
|
||||||
if (mTickMarkId != 0) {
|
if (mTickMarkId != 0) {
|
||||||
final Drawable tickMark = getContext().getDrawable(mTickMarkId);
|
final Drawable tickMark = getContext().getDrawable(mTickMarkId);
|
||||||
seekBar.setTickMark(tickMark);
|
mSeekBar.setTickMark(tickMark);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ViewGroup iconStartFrame = (ViewGroup) holder.findViewById(R.id.icon_start_frame);
|
final ViewGroup iconStartFrame = (ViewGroup) holder.findViewById(R.id.icon_start_frame);
|
||||||
final ImageView iconStartView = (ImageView) holder.findViewById(R.id.icon_start);
|
final ImageView iconStartView = (ImageView) holder.findViewById(R.id.icon_start);
|
||||||
updateIconStartIfNeeded(iconStartFrame, iconStartView, seekBar);
|
updateIconStartIfNeeded(iconStartFrame, iconStartView, mSeekBar);
|
||||||
|
|
||||||
final ViewGroup iconEndFrame = (ViewGroup) holder.findViewById(R.id.icon_end_frame);
|
final ViewGroup iconEndFrame = (ViewGroup) holder.findViewById(R.id.icon_end_frame);
|
||||||
final ImageView iconEndView = (ImageView) holder.findViewById(R.id.icon_end);
|
final ImageView iconEndView = (ImageView) holder.findViewById(R.id.icon_end);
|
||||||
updateIconEndIfNeeded(iconEndFrame, iconEndView, seekBar);
|
updateIconEndIfNeeded(iconEndFrame, iconEndView, mSeekBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOnPreferenceChangeStopListener(OnPreferenceChangeListener listener) {
|
public void setOnPreferenceChangeStopListener(OnPreferenceChangeListener listener) {
|
||||||
|
|||||||
@@ -16,29 +16,45 @@
|
|||||||
|
|
||||||
package com.android.settings.accessibility;
|
package com.android.settings.accessibility;
|
||||||
|
|
||||||
|
import static com.android.internal.accessibility.AccessibilityShortcutController.FONT_SIZE_COMPONENT_NAME;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.widget.PopupWindow;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
|
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.SettingsPreferenceFragment;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowFragment;
|
||||||
import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor;
|
import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor;
|
||||||
import com.android.settings.widget.LabeledSeekBarPreference;
|
import com.android.settings.widget.LabeledSeekBarPreference;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.mockito.Spy;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadow.api.Shadow;
|
||||||
|
import org.robolectric.shadows.ShadowApplication;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link PreviewSizeSeekBarController}.
|
* Tests for {@link PreviewSizeSeekBarController}.
|
||||||
@@ -47,30 +63,67 @@ import org.robolectric.annotation.Config;
|
|||||||
@Config(shadows = {ShadowInteractionJankMonitor.class})
|
@Config(shadows = {ShadowInteractionJankMonitor.class})
|
||||||
public class PreviewSizeSeekBarControllerTest {
|
public class PreviewSizeSeekBarControllerTest {
|
||||||
private static final String FONT_SIZE_KEY = "font_size";
|
private static final String FONT_SIZE_KEY = "font_size";
|
||||||
|
private static final String KEY_SAVED_QS_TOOLTIP_RESHOW = "qs_tooltip_reshow";
|
||||||
|
@Spy
|
||||||
private final Context mContext = ApplicationProvider.getApplicationContext();
|
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||||
private PreviewSizeSeekBarController mSeekBarController;
|
private PreviewSizeSeekBarController mSeekBarController;
|
||||||
private FontSizeData mFontSizeData;
|
private FontSizeData mFontSizeData;
|
||||||
private LabeledSeekBarPreference mSeekBarPreference;
|
private LabeledSeekBarPreference mSeekBarPreference;
|
||||||
|
|
||||||
@Mock
|
|
||||||
private PreferenceScreen mPreferenceScreen;
|
private PreferenceScreen mPreferenceScreen;
|
||||||
|
private TestFragment mFragment;
|
||||||
|
private PreferenceViewHolder mHolder;
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private PreferenceManager mPreferenceManager;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private PreviewSizeSeekBarController.ProgressInteractionListener mInteractionListener;
|
private PreviewSizeSeekBarController.ProgressInteractionListener mInteractionListener;
|
||||||
|
|
||||||
|
private static PopupWindow getLatestPopupWindow() {
|
||||||
|
final ShadowApplication shadowApplication =
|
||||||
|
Shadow.extract(ApplicationProvider.getApplicationContext());
|
||||||
|
return shadowApplication.getLatestPopupWindow();
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
mFontSizeData = new FontSizeData(mContext);
|
mContext.setTheme(R.style.Theme_AppCompat);
|
||||||
|
mFragment = spy(new TestFragment());
|
||||||
mSeekBarController =
|
when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager);
|
||||||
new PreviewSizeSeekBarController(mContext, FONT_SIZE_KEY, mFontSizeData);
|
when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext);
|
||||||
|
when(mFragment.getContext()).thenReturn(mContext);
|
||||||
|
mPreferenceScreen = spy(new PreferenceScreen(mContext, /* attrs= */ null));
|
||||||
|
when(mPreferenceScreen.getPreferenceManager()).thenReturn(mPreferenceManager);
|
||||||
|
doReturn(mPreferenceScreen).when(mFragment).getPreferenceScreen();
|
||||||
mSeekBarPreference = spy(new LabeledSeekBarPreference(mContext, /* attrs= */ null));
|
mSeekBarPreference = spy(new LabeledSeekBarPreference(mContext, /* attrs= */ null));
|
||||||
|
mSeekBarPreference.setKey(FONT_SIZE_KEY);
|
||||||
|
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||||
|
mHolder = PreferenceViewHolder.createInstanceForTests(inflater.inflate(
|
||||||
|
R.layout.preference_labeled_slider, null));
|
||||||
|
mSeekBarPreference.onBindViewHolder(mHolder);
|
||||||
|
|
||||||
when(mPreferenceScreen.findPreference(anyString())).thenReturn(mSeekBarPreference);
|
when(mPreferenceScreen.findPreference(anyString())).thenReturn(mSeekBarPreference);
|
||||||
|
|
||||||
|
mFontSizeData = new FontSizeData(mContext);
|
||||||
|
mSeekBarController =
|
||||||
|
new PreviewSizeSeekBarController(mContext, FONT_SIZE_KEY, mFontSizeData) {
|
||||||
|
@Override
|
||||||
|
ComponentName getTileComponentName() {
|
||||||
|
return FONT_SIZE_COMPONENT_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
CharSequence getTileTooltipContent() {
|
||||||
|
return mContext.getText(
|
||||||
|
R.string.accessibility_font_scaling_auto_added_qs_tooltip_content);
|
||||||
|
}
|
||||||
|
};
|
||||||
mSeekBarController.setInteractionListener(mInteractionListener);
|
mSeekBarController.setInteractionListener(mInteractionListener);
|
||||||
|
when(mPreferenceScreen.findPreference(mSeekBarController.getPreferenceKey())).thenReturn(
|
||||||
|
mSeekBarPreference);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -123,4 +176,64 @@ public class PreviewSizeSeekBarControllerTest {
|
|||||||
|
|
||||||
verify(mInteractionListener).notifyPreferenceChanged();
|
verify(mInteractionListener).notifyPreferenceChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onProgressChanged_showTooltipView() {
|
||||||
|
mSeekBarController.displayPreference(mPreferenceScreen);
|
||||||
|
|
||||||
|
// Simulate changing the progress for the first time
|
||||||
|
int newProgress = (mSeekBarPreference.getProgress() != 0) ? 0 : mSeekBarPreference.getMax();
|
||||||
|
mSeekBarPreference.setProgress(newProgress);
|
||||||
|
mSeekBarPreference.onProgressChanged(new SeekBar(mContext),
|
||||||
|
newProgress,
|
||||||
|
/* fromUser= */ false);
|
||||||
|
|
||||||
|
assertThat(getLatestPopupWindow().isShowing()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onProgressChanged_tooltipViewHasBeenShown_notShowTooltipView() {
|
||||||
|
mSeekBarController.displayPreference(mPreferenceScreen);
|
||||||
|
// Simulate changing the progress for the first time
|
||||||
|
int newProgress = (mSeekBarPreference.getProgress() != 0) ? 0 : mSeekBarPreference.getMax();
|
||||||
|
mSeekBarPreference.setProgress(newProgress);
|
||||||
|
mSeekBarPreference.onProgressChanged(new SeekBar(mContext),
|
||||||
|
newProgress,
|
||||||
|
/* fromUser= */ false);
|
||||||
|
getLatestPopupWindow().dismiss();
|
||||||
|
|
||||||
|
// Simulate progress changing for the second time
|
||||||
|
newProgress = (mSeekBarPreference.getProgress() != 0) ? 0 : mSeekBarPreference.getMax();
|
||||||
|
mSeekBarPreference.setProgress(newProgress);
|
||||||
|
mSeekBarPreference.onProgressChanged(new SeekBar(mContext),
|
||||||
|
newProgress,
|
||||||
|
/* fromUser= */ false);
|
||||||
|
|
||||||
|
assertThat(getLatestPopupWindow().isShowing()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Config(shadows = ShadowFragment.class)
|
||||||
|
public void restoreValueFromSavedInstanceState_showTooltipView() {
|
||||||
|
final Bundle savedInstanceState = new Bundle();
|
||||||
|
savedInstanceState.putBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW, /* value= */ true);
|
||||||
|
mSeekBarController.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
mSeekBarController.displayPreference(mPreferenceScreen);
|
||||||
|
|
||||||
|
assertThat(getLatestPopupWindow().isShowing()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TestFragment extends SettingsPreferenceFragment {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldSkipForInitialSUW() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMetricsCategory() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,13 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
@@ -30,6 +35,8 @@ import static org.mockito.Mockito.when;
|
|||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
@@ -215,29 +222,89 @@ public class SettingsHomepageActivityTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Config(shadows = {ShadowPasswordUtils.class})
|
public void getInitialReferrer_differentPackage_returnCurrentReferrer() {
|
||||||
|
SettingsHomepageActivity activity =
|
||||||
|
spy(Robolectric.buildActivity(SettingsHomepageActivity.class).get());
|
||||||
|
String referrer = "com.abc";
|
||||||
|
doReturn(referrer).when(activity).getCurrentReferrer();
|
||||||
|
|
||||||
|
assertEquals(activity.getInitialReferrer(), referrer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getInitialReferrer_noReferrerExtra_returnCurrentReferrer() {
|
||||||
|
SettingsHomepageActivity activity =
|
||||||
|
spy(Robolectric.buildActivity(SettingsHomepageActivity.class).get());
|
||||||
|
String referrer = activity.getPackageName();
|
||||||
|
doReturn(referrer).when(activity).getCurrentReferrer();
|
||||||
|
|
||||||
|
assertEquals(activity.getInitialReferrer(), referrer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getInitialReferrer_hasReferrerExtra_returnGivenReferrer() {
|
||||||
|
SettingsHomepageActivity activity =
|
||||||
|
spy(Robolectric.buildActivity(SettingsHomepageActivity.class).get());
|
||||||
|
doReturn(activity.getPackageName()).when(activity).getCurrentReferrer();
|
||||||
|
String referrer = "com.abc";
|
||||||
|
activity.setIntent(new Intent().putExtra(SettingsHomepageActivity.EXTRA_INITIAL_REFERRER,
|
||||||
|
referrer));
|
||||||
|
|
||||||
|
assertEquals(activity.getInitialReferrer(), referrer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCurrentReferrer_hasReferrerExtra_shouldNotEqual() {
|
||||||
|
String referrer = "com.abc";
|
||||||
|
Uri uri = new Uri.Builder().scheme("android-app").authority(referrer).build();
|
||||||
|
SettingsHomepageActivity activity =
|
||||||
|
spy(Robolectric.buildActivity(SettingsHomepageActivity.class).get());
|
||||||
|
activity.setIntent(new Intent().putExtra(Intent.EXTRA_REFERRER, uri));
|
||||||
|
|
||||||
|
assertNotEquals(activity.getCurrentReferrer(), referrer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getCurrentReferrer_hasReferrerNameExtra_shouldNotEqual() {
|
||||||
|
String referrer = "com.abc";
|
||||||
|
SettingsHomepageActivity activity =
|
||||||
|
spy(Robolectric.buildActivity(SettingsHomepageActivity.class).get());
|
||||||
|
activity.setIntent(new Intent().putExtra(Intent.EXTRA_REFERRER_NAME, referrer));
|
||||||
|
|
||||||
|
assertNotEquals(activity.getCurrentReferrer(), referrer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void isCallingAppPermitted_emptyPermission_returnTrue() {
|
public void isCallingAppPermitted_emptyPermission_returnTrue() {
|
||||||
SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
|
SettingsHomepageActivity activity =
|
||||||
|
spy(Robolectric.buildActivity(SettingsHomepageActivity.class).get());
|
||||||
|
doReturn(PackageManager.PERMISSION_DENIED).when(activity)
|
||||||
|
.checkPermission(anyString(), anyInt(), anyInt());
|
||||||
|
|
||||||
assertTrue(homepageActivity.isCallingAppPermitted(""));
|
assertTrue(activity.isCallingAppPermitted("", 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Config(shadows = {ShadowPasswordUtils.class})
|
public void isCallingAppPermitted_notGrantedPermission_returnFalse() {
|
||||||
public void isCallingAppPermitted_noGrantedPermission_returnFalse() {
|
SettingsHomepageActivity activity =
|
||||||
SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
|
spy(Robolectric.buildActivity(SettingsHomepageActivity.class).get());
|
||||||
|
doReturn(PackageManager.PERMISSION_DENIED).when(activity)
|
||||||
|
.checkPermission(anyString(), anyInt(), anyInt());
|
||||||
|
|
||||||
assertFalse(homepageActivity.isCallingAppPermitted("android.permission.TEST"));
|
assertFalse(activity.isCallingAppPermitted("android.permission.TEST", 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Config(shadows = {ShadowPasswordUtils.class})
|
|
||||||
public void isCallingAppPermitted_grantedPermission_returnTrue() {
|
public void isCallingAppPermitted_grantedPermission_returnTrue() {
|
||||||
SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
|
SettingsHomepageActivity activity =
|
||||||
|
spy(Robolectric.buildActivity(SettingsHomepageActivity.class).get());
|
||||||
String permission = "android.permission.TEST";
|
String permission = "android.permission.TEST";
|
||||||
ShadowPasswordUtils.addGrantedPermission(permission);
|
doReturn(PackageManager.PERMISSION_DENIED).when(activity)
|
||||||
|
.checkPermission(anyString(), anyInt(), anyInt());
|
||||||
|
doReturn(PackageManager.PERMISSION_GRANTED).when(activity)
|
||||||
|
.checkPermission(eq(permission), anyInt(), eq(1000));
|
||||||
|
|
||||||
assertTrue(homepageActivity.isCallingAppPermitted(permission));
|
assertTrue(activity.isCallingAppPermitted(permission, 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Implements(SuggestionFeatureProviderImpl.class)
|
@Implements(SuggestionFeatureProviderImpl.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user