DO NOT MERGE - Merge qt-qpr1-dev-plus-aosp-without-vendor (6129114) into stage-aosp-master
Bug: 146167222 Change-Id: I77344517b74a2192af49a3f8956d8756b81741d9
This commit is contained in:
@@ -24,7 +24,6 @@ import android.provider.SearchIndexableResource;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.display.BrightnessLevelPreferenceController;
|
||||
import com.android.settings.display.CameraGesturePreferenceController;
|
||||
import com.android.settings.display.DarkUIPreferenceController;
|
||||
import com.android.settings.display.LiftToWakePreferenceController;
|
||||
import com.android.settings.display.NightDisplayPreferenceController;
|
||||
import com.android.settings.display.NightModePreferenceController;
|
||||
@@ -67,7 +66,6 @@ public class DisplaySettings extends DashboardFragment {
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
use(DarkUIPreferenceController.class).setParentFragment(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -52,6 +52,7 @@ public class Settings extends SettingsActivity {
|
||||
public static class LocalePickerActivity extends SettingsActivity { /* empty */ }
|
||||
public static class LanguageAndInputSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class UserDictionarySettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class DarkThemeSettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class DisplaySettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class NightDisplaySettingsActivity extends SettingsActivity { /* empty */ }
|
||||
public static class NightDisplaySuggestionActivity extends NightDisplaySettingsActivity { /* empty */ }
|
||||
|
@@ -26,6 +26,7 @@ import android.widget.TextView;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.biometrics.BiometricEnrollIntroduction;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
|
||||
@@ -40,12 +41,15 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
private static final String TAG = "FaceIntro";
|
||||
|
||||
private FaceManager mFaceManager;
|
||||
private FaceFeatureProvider mFaceFeatureProvider;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mFaceManager = Utils.getFaceManagerOrNull(this);
|
||||
mFaceFeatureProvider = FeatureFactory.getFactory(getApplicationContext())
|
||||
.getFaceFeatureProvider();
|
||||
|
||||
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
|
||||
if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
|
||||
@@ -87,6 +91,12 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
|
||||
});
|
||||
}
|
||||
|
||||
final TextView footer2 = findViewById(R.id.face_enroll_introduction_footer_part_2);
|
||||
final int footer2TextResource =
|
||||
mFaceFeatureProvider.isAttentionSupported(getApplicationContext())
|
||||
? R.string.security_settings_face_enroll_introduction_footer_part_2
|
||||
: R.string.security_settings_face_settings_footer_attention_not_supported;
|
||||
footer2.setText(footer2TextResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.settings.biometrics.face;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/** Feature provider for face unlock */
|
||||
public interface FaceFeatureProvider {
|
||||
/** Returns true if attention checking is supported. */
|
||||
boolean isAttentionSupported(Context context);
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.settings.biometrics.face;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
|
||||
public class FaceFeatureProviderImpl implements FaceFeatureProvider {
|
||||
|
||||
@Override
|
||||
public boolean isAttentionSupported(Context context) {
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -37,6 +37,7 @@ import com.android.settings.R;
|
||||
import com.android.settings.SettingsActivity;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
@@ -60,13 +61,16 @@ public class FaceSettings extends DashboardFragment {
|
||||
private FaceManager mFaceManager;
|
||||
private int mUserId;
|
||||
private byte[] mToken;
|
||||
private FaceSettingsAttentionPreferenceController mAttentionController;
|
||||
private FaceSettingsRemoveButtonPreferenceController mRemoveController;
|
||||
private FaceSettingsEnrollButtonPreferenceController mEnrollController;
|
||||
private FaceSettingsLockscreenBypassPreferenceController mLockscreenController;
|
||||
private List<AbstractPreferenceController> mControllers;
|
||||
|
||||
private List<Preference> mTogglePreferences;
|
||||
private Preference mRemoveButton;
|
||||
private Preference mEnrollButton;
|
||||
private FaceFeatureProvider mFaceFeatureProvider;
|
||||
|
||||
private boolean mConfirmingPassword;
|
||||
|
||||
@@ -117,6 +121,7 @@ public class FaceSettings extends DashboardFragment {
|
||||
mFaceManager = getPrefContext().getSystemService(FaceManager.class);
|
||||
mUserId = getActivity().getIntent().getIntExtra(
|
||||
Intent.EXTRA_USER_ID, UserHandle.myUserId());
|
||||
mFaceFeatureProvider = FeatureFactory.getFactory(getContext()).getFaceFeatureProvider();
|
||||
|
||||
if (mUserManager.getUserInfo(mUserId).isManagedProfile()) {
|
||||
getActivity().setTitle(getActivity().getResources().getString(
|
||||
@@ -125,18 +130,19 @@ public class FaceSettings extends DashboardFragment {
|
||||
|
||||
Preference keyguardPref = findPreference(FaceSettingsKeyguardPreferenceController.KEY);
|
||||
Preference appPref = findPreference(FaceSettingsAppPreferenceController.KEY);
|
||||
Preference attentionPref = findPreference(FaceSettingsAttentionPreferenceController.KEY);
|
||||
Preference confirmPref = findPreference(FaceSettingsConfirmPreferenceController.KEY);
|
||||
Preference bypassPref =
|
||||
findPreference(FaceSettingsLockscreenBypassPreferenceController.KEY);
|
||||
findPreference(mLockscreenController.getPreferenceKey());
|
||||
mTogglePreferences = new ArrayList<>(
|
||||
Arrays.asList(keyguardPref, appPref, confirmPref, bypassPref));
|
||||
Arrays.asList(keyguardPref, appPref, attentionPref, confirmPref, bypassPref));
|
||||
|
||||
mRemoveButton = findPreference(FaceSettingsRemoveButtonPreferenceController.KEY);
|
||||
mEnrollButton = findPreference(FaceSettingsEnrollButtonPreferenceController.KEY);
|
||||
|
||||
// There is no better way to do this :/
|
||||
for (AbstractPreferenceController controller : mControllers) {
|
||||
if (controller instanceof FaceSettingsPreferenceController) {
|
||||
if (controller instanceof FaceSettingsPreferenceController) {
|
||||
((FaceSettingsPreferenceController) controller).setUserId(mUserId);
|
||||
} else if (controller instanceof FaceSettingsEnrollButtonPreferenceController) {
|
||||
((FaceSettingsEnrollButtonPreferenceController) controller).setUserId(mUserId);
|
||||
@@ -147,6 +153,7 @@ public class FaceSettings extends DashboardFragment {
|
||||
// Don't show keyguard controller for work profile settings.
|
||||
if (mUserManager.isManagedProfile(mUserId)) {
|
||||
removePreference(FaceSettingsKeyguardPreferenceController.KEY);
|
||||
removePreference(mLockscreenController.getPreferenceKey());
|
||||
}
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
@@ -154,6 +161,14 @@ public class FaceSettings extends DashboardFragment {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
|
||||
mLockscreenController = use(FaceSettingsLockscreenBypassPreferenceController.class);
|
||||
mLockscreenController.setUserId(mUserId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
@@ -173,12 +188,17 @@ public class FaceSettings extends DashboardFragment {
|
||||
finish();
|
||||
}
|
||||
} else {
|
||||
mAttentionController.setToken(mToken);
|
||||
mEnrollController.setToken(mToken);
|
||||
}
|
||||
|
||||
final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId);
|
||||
mEnrollButton.setVisible(!hasEnrolled);
|
||||
mRemoveButton.setVisible(hasEnrolled);
|
||||
|
||||
if (!mFaceFeatureProvider.isAttentionSupported(getContext())) {
|
||||
removePreference(FaceSettingsAttentionPreferenceController.KEY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -193,6 +213,7 @@ public class FaceSettings extends DashboardFragment {
|
||||
mToken = data.getByteArrayExtra(
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
|
||||
if (mToken != null) {
|
||||
mAttentionController.setToken(mToken);
|
||||
mEnrollController.setToken(mToken);
|
||||
}
|
||||
}
|
||||
@@ -236,7 +257,9 @@ public class FaceSettings extends DashboardFragment {
|
||||
mControllers = buildPreferenceControllers(context, getSettingsLifecycle());
|
||||
// There's no great way of doing this right now :/
|
||||
for (AbstractPreferenceController controller : mControllers) {
|
||||
if (controller instanceof FaceSettingsRemoveButtonPreferenceController) {
|
||||
if (controller instanceof FaceSettingsAttentionPreferenceController) {
|
||||
mAttentionController = (FaceSettingsAttentionPreferenceController) controller;
|
||||
} else if (controller instanceof FaceSettingsRemoveButtonPreferenceController) {
|
||||
mRemoveController = (FaceSettingsRemoveButtonPreferenceController) controller;
|
||||
mRemoveController.setListener(mRemovalListener);
|
||||
mRemoveController.setActivity((SettingsActivity) getActivity());
|
||||
@@ -255,6 +278,7 @@ public class FaceSettings extends DashboardFragment {
|
||||
controllers.add(new FaceSettingsVideoPreferenceController(context));
|
||||
controllers.add(new FaceSettingsKeyguardPreferenceController(context));
|
||||
controllers.add(new FaceSettingsAppPreferenceController(context));
|
||||
controllers.add(new FaceSettingsAttentionPreferenceController(context));
|
||||
controllers.add(new FaceSettingsRemoveButtonPreferenceController(context));
|
||||
controllers.add(new FaceSettingsFooterPreferenceController(context));
|
||||
controllers.add(new FaceSettingsConfirmPreferenceController(context));
|
||||
|
@@ -23,6 +23,7 @@ import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.utils.AnnotationSpan;
|
||||
import com.android.settingslib.HelpUtils;
|
||||
import com.android.settingslib.widget.FooterPreference;
|
||||
@@ -34,8 +35,11 @@ public class FaceSettingsFooterPreferenceController extends BasePreferenceContro
|
||||
|
||||
private static final String ANNOTATION_URL = "url";
|
||||
|
||||
private FaceFeatureProvider mProvider;
|
||||
|
||||
public FaceSettingsFooterPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mProvider = FeatureFactory.getFactory(context).getFaceFeatureProvider();
|
||||
}
|
||||
|
||||
public FaceSettingsFooterPreferenceController(Context context) {
|
||||
@@ -55,7 +59,12 @@ public class FaceSettingsFooterPreferenceController extends BasePreferenceContro
|
||||
mContext, mContext.getString(R.string.help_url_face), getClass().getName());
|
||||
final AnnotationSpan.LinkInfo linkInfo =
|
||||
new AnnotationSpan.LinkInfo(mContext, ANNOTATION_URL, helpIntent);
|
||||
|
||||
final int footerRes = mProvider.isAttentionSupported(mContext)
|
||||
? R.string.security_settings_face_settings_footer
|
||||
: R.string.security_settings_face_settings_footer_attention_not_supported;
|
||||
|
||||
preference.setTitle(AnnotationSpan.linkify(
|
||||
mContext.getText(R.string.security_settings_face_settings_footer), linkInfo));
|
||||
mContext.getText(footerRes), linkInfo));
|
||||
}
|
||||
}
|
||||
|
@@ -30,8 +30,6 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
public class FaceSettingsLockscreenBypassPreferenceController
|
||||
extends FaceSettingsPreferenceController {
|
||||
|
||||
static final String KEY = "security_lockscreen_bypass";
|
||||
|
||||
@VisibleForTesting
|
||||
protected FaceManager mFaceManager;
|
||||
private UserManager mUserManager;
|
||||
|
@@ -60,6 +60,7 @@ import java.util.Map;
|
||||
public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceController implements
|
||||
LifecycleObserver, OnStart, OnStop, OnDestroy, CachedBluetoothDevice.Callback {
|
||||
private static final String TAG = "AdvancedBtHeaderCtrl";
|
||||
private static final int LOW_BATTERY_LEVEL = 20;
|
||||
|
||||
@VisibleForTesting
|
||||
LayoutPreference mLayoutPreference;
|
||||
@@ -180,12 +181,18 @@ public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceCont
|
||||
Drawable createBtBatteryIcon(Context context, int level, boolean charging) {
|
||||
final BatteryMeterView.BatteryMeterDrawable drawable =
|
||||
new BatteryMeterView.BatteryMeterDrawable(context,
|
||||
context.getColor(R.color.meter_background_color));
|
||||
context.getColor(R.color.meter_background_color),
|
||||
context.getResources().getDimensionPixelSize(
|
||||
R.dimen.advanced_bluetooth_battery_meter_width),
|
||||
context.getResources().getDimensionPixelSize(
|
||||
R.dimen.advanced_bluetooth_battery_meter_height));
|
||||
drawable.setBatteryLevel(level);
|
||||
final int attr = level > LOW_BATTERY_LEVEL || charging
|
||||
? android.R.attr.colorControlNormal
|
||||
: android.R.attr.colorError;
|
||||
drawable.setColorFilter(new PorterDuffColorFilter(
|
||||
com.android.settings.Utils.getColorAttrDefaultColor(context,
|
||||
android.R.attr.colorControlNormal),
|
||||
PorterDuff.Mode.SRC_IN));
|
||||
com.android.settings.Utils.getColorAttrDefaultColor(context, attr),
|
||||
PorterDuff.Mode.SRC));
|
||||
drawable.setCharging(charging);
|
||||
|
||||
return drawable;
|
||||
|
@@ -136,6 +136,6 @@ public class BluetoothSliceBuilder {
|
||||
final Intent intent = new Intent(ACTION_BLUETOOTH_SLICE_CHANGED)
|
||||
.setClass(context, SliceBroadcastReceiver.class);
|
||||
return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ package com.android.settings.core;
|
||||
|
||||
import android.annotation.LayoutRes;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -26,6 +27,7 @@ import android.content.pm.PackageManager;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -61,6 +63,10 @@ public class SettingsBaseActivity extends FragmentActivity {
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (isLockTaskModePinned() && !isSettingsRunOnTop()) {
|
||||
Log.w(TAG, "Devices lock task mode pinned.");
|
||||
finish();
|
||||
}
|
||||
final long startTime = System.currentTimeMillis();
|
||||
getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
|
||||
|
||||
@@ -148,6 +154,20 @@ public class SettingsBaseActivity extends FragmentActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLockTaskModePinned() {
|
||||
final ActivityManager activityManager =
|
||||
getApplicationContext().getSystemService(ActivityManager.class);
|
||||
return activityManager.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_PINNED;
|
||||
}
|
||||
|
||||
private boolean isSettingsRunOnTop() {
|
||||
final ActivityManager activityManager =
|
||||
getApplicationContext().getSystemService(ActivityManager.class);
|
||||
final String taskPkgName = activityManager.getRunningTasks(1 /* maxNum */)
|
||||
.get(0 /* index */).baseActivity.getPackageName();
|
||||
return TextUtils.equals(getPackageName(), taskPkgName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether or not the enabled state actually changed.
|
||||
*/
|
||||
|
@@ -74,6 +74,7 @@ import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment;
|
||||
import com.android.settings.deviceinfo.firmwareversion.FirmwareVersionSettings;
|
||||
import com.android.settings.deviceinfo.legal.ModuleLicensesDashboard;
|
||||
import com.android.settings.display.NightDisplaySettings;
|
||||
import com.android.settings.display.darkmode.DarkModeSettingsFragment;
|
||||
import com.android.settings.dream.DreamSettings;
|
||||
import com.android.settings.enterprise.EnterprisePrivacySettings;
|
||||
import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
|
||||
@@ -281,7 +282,8 @@ public class SettingsGateway {
|
||||
PreviouslyConnectedDeviceDashboardFragment.class.getName(),
|
||||
BatterySaverScheduleSettings.class.getName(),
|
||||
MobileNetworkListFragment.class.getName(),
|
||||
GlobalActionsPanelSettings.class.getName()
|
||||
GlobalActionsPanelSettings.class.getName(),
|
||||
DarkModeSettingsFragment.class.getName()
|
||||
};
|
||||
|
||||
public static final String[] SETTINGS_FOR_RESTRICTED = {
|
||||
|
@@ -111,7 +111,7 @@ public class MainlineModuleVersionPreferenceController extends BasePreferenceCon
|
||||
try {
|
||||
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern,
|
||||
Locale.getDefault());
|
||||
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
simpleDateFormat.setTimeZone(TimeZone.getDefault());
|
||||
return Optional.of(simpleDateFormat.parse(text));
|
||||
} catch (ParseException e) {
|
||||
// ignore and try next pattern
|
||||
|
@@ -21,6 +21,7 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
|
||||
@@ -28,7 +29,6 @@ import androidx.annotation.VisibleForTesting;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
@@ -44,7 +44,7 @@ public class DarkUIPreferenceController extends TogglePreferenceController imple
|
||||
public static final int DIALOG_SEEN = 1;
|
||||
|
||||
@VisibleForTesting
|
||||
SwitchPreference mPreference;
|
||||
Preference mPreference;
|
||||
|
||||
private UiModeManager mUiModeManager;
|
||||
private PowerManager mPowerManager;
|
||||
@@ -68,7 +68,8 @@ public class DarkUIPreferenceController extends TogglePreferenceController imple
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES;
|
||||
return (mContext.getResources().getConfiguration().uiMode
|
||||
& Configuration.UI_MODE_NIGHT_YES) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -90,17 +91,13 @@ public class DarkUIPreferenceController extends TogglePreferenceController imple
|
||||
Settings.Secure.DARK_MODE_DIALOG_SEEN, 0) == DIALOG_SEEN;
|
||||
if (!dialogSeen && isChecked) {
|
||||
showDarkModeDialog();
|
||||
return false;
|
||||
}
|
||||
mUiModeManager.setNightMode(isChecked
|
||||
? UiModeManager.MODE_NIGHT_YES
|
||||
: UiModeManager.MODE_NIGHT_NO);
|
||||
return true;
|
||||
return mUiModeManager.setNightModeActivated(isChecked);
|
||||
}
|
||||
|
||||
private void showDarkModeDialog() {
|
||||
final DarkUIInfoDialogFragment frag = new DarkUIInfoDialogFragment();
|
||||
if (mFragment.getFragmentManager() != null) {
|
||||
if (mFragment != null && mFragment.getFragmentManager() != null) {
|
||||
frag.show(mFragment.getFragmentManager(), getClass().getName());
|
||||
}
|
||||
}
|
||||
@@ -113,12 +110,10 @@ public class DarkUIPreferenceController extends TogglePreferenceController imple
|
||||
boolean isBatterySaver = isPowerSaveMode();
|
||||
mPreference.setEnabled(!isBatterySaver);
|
||||
if (isBatterySaver) {
|
||||
int stringId = mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES
|
||||
int stringId = isChecked()
|
||||
? R.string.dark_ui_mode_disabled_summary_dark_theme_on
|
||||
: R.string.dark_ui_mode_disabled_summary_dark_theme_off;
|
||||
mPreference.setSummary(mContext.getString(stringId));
|
||||
} else {
|
||||
mPreference.setSummary(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,22 +122,17 @@ public class DarkUIPreferenceController extends TogglePreferenceController imple
|
||||
return mPowerManager.isPowerSaveMode();
|
||||
}
|
||||
|
||||
|
||||
@VisibleForTesting
|
||||
void setUiModeManager(UiModeManager uiModeManager) {
|
||||
mUiModeManager = uiModeManager;
|
||||
}
|
||||
|
||||
public void setParentFragment(Fragment fragment) {
|
||||
mFragment = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
mContext.registerReceiver(mReceiver,
|
||||
new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
|
||||
}
|
||||
|
||||
// used by AccessibilitySettings
|
||||
public void setParentFragment(Fragment fragment) {
|
||||
mFragment = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
mContext.unregisterReceiver(mReceiver);
|
||||
|
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.display.darkmode;
|
||||
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.PowerManager;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.widget.LayoutPreference;
|
||||
|
||||
/**
|
||||
* Controller for activate/deactivate night mode button
|
||||
*/
|
||||
public class DarkModeActivationPreferenceController extends BasePreferenceController {
|
||||
private final UiModeManager mUiModeManager;
|
||||
private PowerManager mPowerManager;
|
||||
private Button mTurnOffButton;
|
||||
private Button mTurnOnButton;
|
||||
|
||||
public DarkModeActivationPreferenceController(Context context,
|
||||
String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mPowerManager = context.getSystemService(PowerManager.class);
|
||||
mUiModeManager = context.getSystemService(UiModeManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void updateState(Preference preference) {
|
||||
|
||||
final boolean batterySaver = mPowerManager.isPowerSaveMode();
|
||||
if (batterySaver) {
|
||||
mTurnOnButton.setVisibility(View.GONE);
|
||||
mTurnOffButton.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean active = (mContext.getResources().getConfiguration().uiMode
|
||||
& Configuration.UI_MODE_NIGHT_YES) != 0;
|
||||
updateNightMode(active);
|
||||
}
|
||||
|
||||
private void updateNightMode(boolean active) {
|
||||
final int autoMode = mUiModeManager.getNightMode();
|
||||
String buttonText;
|
||||
|
||||
if (autoMode == UiModeManager.MODE_NIGHT_AUTO) {
|
||||
buttonText = mContext.getString(active
|
||||
? R.string.dark_ui_activation_off_auto
|
||||
: R.string.dark_ui_activation_on_auto);
|
||||
} else {
|
||||
buttonText = mContext.getString(active
|
||||
? R.string.dark_ui_activation_off_manual
|
||||
: R.string.dark_ui_activation_on_manual);
|
||||
}
|
||||
if (active) {
|
||||
mTurnOnButton.setVisibility(View.GONE);
|
||||
mTurnOffButton.setVisibility(View.VISIBLE);
|
||||
mTurnOffButton.setText(buttonText);
|
||||
} else {
|
||||
mTurnOnButton.setVisibility(View.VISIBLE);
|
||||
mTurnOffButton.setVisibility(View.GONE);
|
||||
mTurnOnButton.setText(buttonText);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
final boolean isActivated = (mContext.getResources().getConfiguration().uiMode
|
||||
& Configuration.UI_MODE_NIGHT_YES) != 0;
|
||||
final int autoMode = mUiModeManager.getNightMode();
|
||||
if (autoMode == UiModeManager.MODE_NIGHT_AUTO) {
|
||||
return mContext.getString(isActivated
|
||||
? R.string.dark_ui_summary_on_auto_mode_auto
|
||||
: R.string.dark_ui_summary_off_auto_mode_auto);
|
||||
} else {
|
||||
return mContext.getString(isActivated
|
||||
? R.string.dark_ui_summary_on_auto_mode_never
|
||||
: R.string.dark_ui_summary_off_auto_mode_never);
|
||||
}
|
||||
}
|
||||
|
||||
private final View.OnClickListener mListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final boolean active = (mContext.getResources().getConfiguration().uiMode
|
||||
& Configuration.UI_MODE_NIGHT_YES) != 0;
|
||||
mUiModeManager.setNightModeActivated(!active);
|
||||
updateNightMode(!active);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
|
||||
final LayoutPreference preference = screen.findPreference(getPreferenceKey());
|
||||
mTurnOnButton = preference.findViewById(R.id.dark_ui_turn_on_button);
|
||||
mTurnOnButton.setOnClickListener(mListener);
|
||||
mTurnOffButton = preference.findViewById(R.id.dark_ui_turn_off_button);
|
||||
mTurnOffButton.setOnClickListener(mListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
}
|
103
src/com/android/settings/display/darkmode/DarkModeObserver.java
Normal file
103
src/com/android/settings/display/darkmode/DarkModeObserver.java
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.display.darkmode;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Observes changes for dark night settings*/
|
||||
public class DarkModeObserver {
|
||||
private static final String TAG = "DarkModeObserver";
|
||||
private ContentObserver mContentObserver;
|
||||
private final BroadcastReceiver mBatterySaverReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
mCallback.run();
|
||||
}
|
||||
};
|
||||
private Runnable mCallback;
|
||||
private Context mContext;
|
||||
|
||||
public DarkModeObserver(Context context) {
|
||||
mContext = context;
|
||||
mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
super.onChange(selfChange, uri);
|
||||
final String setting = uri == null ? null : uri.getLastPathSegment();
|
||||
if (setting != null && mCallback != null) {
|
||||
switch (setting) {
|
||||
case Settings.Secure.UI_NIGHT_MODE:
|
||||
mCallback.run();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* subscribe callback when night mode changed in the database
|
||||
*
|
||||
* @param callback the callback that gets triggered when subscribed
|
||||
*/
|
||||
public void subscribe(Runnable callback) {
|
||||
callback.run();
|
||||
mCallback = callback;
|
||||
final Uri uri = Settings.Secure.getUriFor(Settings.Secure.UI_NIGHT_MODE);
|
||||
mContext.getContentResolver().registerContentObserver(uri, false, mContentObserver);
|
||||
final IntentFilter batteryFilter = new IntentFilter();
|
||||
batteryFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
|
||||
mContext.registerReceiver(
|
||||
mBatterySaverReceiver, batteryFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* unsubscribe from dark ui database changes
|
||||
*/
|
||||
public void unsubscribe() {
|
||||
mContext.getContentResolver().unregisterContentObserver(mContentObserver);
|
||||
try {
|
||||
mContext.unregisterReceiver(mBatterySaverReceiver);
|
||||
} catch (IllegalArgumentException e) {
|
||||
/* Ignore: unregistering an unregistered receiver */
|
||||
Log.w(TAG, e.getMessage());
|
||||
}
|
||||
// NO-OP
|
||||
mCallback = null;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void setContentObserver(ContentObserver co) {
|
||||
mContentObserver = co;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected ContentObserver getContentObserver() {
|
||||
return mContentObserver;
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.display.darkmode;
|
||||
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.PowerManager;
|
||||
import android.util.AttributeSet;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.widget.MasterSwitchPreference;
|
||||
|
||||
/**
|
||||
* component for the display settings dark ui summary*/
|
||||
public class DarkModePreference extends MasterSwitchPreference {
|
||||
|
||||
private UiModeManager mUiModeManager;
|
||||
private DarkModeObserver mDarkModeObserver;
|
||||
private PowerManager mPowerManager;
|
||||
private Runnable mCallback;
|
||||
|
||||
public DarkModePreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mDarkModeObserver = new DarkModeObserver(context);
|
||||
mUiModeManager = context.getSystemService(UiModeManager.class);
|
||||
mPowerManager = context.getSystemService(PowerManager.class);
|
||||
mCallback = () -> {
|
||||
final boolean batterySaver = mPowerManager.isPowerSaveMode();
|
||||
final boolean active = (getContext().getResources().getConfiguration().uiMode
|
||||
& Configuration.UI_MODE_NIGHT_YES) != 0;
|
||||
setSwitchEnabled(!batterySaver);
|
||||
updateSummary(batterySaver, active);
|
||||
};
|
||||
mDarkModeObserver.subscribe(mCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttached() {
|
||||
super.onAttached();
|
||||
mDarkModeObserver.subscribe(mCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetached() {
|
||||
super.onDetached();
|
||||
mDarkModeObserver.unsubscribe();
|
||||
}
|
||||
|
||||
private void updateSummary(boolean batterySaver, boolean active) {
|
||||
if (batterySaver) {
|
||||
final int stringId = active ? R.string.dark_ui_mode_disabled_summary_dark_theme_on
|
||||
: R.string.dark_ui_mode_disabled_summary_dark_theme_off;
|
||||
setSummary(getContext().getString(stringId));
|
||||
return;
|
||||
}
|
||||
final boolean auto = mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_AUTO;
|
||||
|
||||
String detail;
|
||||
if (active) {
|
||||
detail = getContext().getString(auto
|
||||
? R.string.dark_ui_summary_on_auto_mode_auto
|
||||
: R.string.dark_ui_summary_on_auto_mode_never);
|
||||
} else {
|
||||
detail = getContext().getString(auto
|
||||
? R.string.dark_ui_summary_off_auto_mode_auto
|
||||
: R.string.dark_ui_summary_off_auto_mode_never);
|
||||
}
|
||||
String summary = getContext().getString(active
|
||||
? R.string.dark_ui_summary_on
|
||||
: R.string.dark_ui_summary_off, detail);
|
||||
|
||||
setSummary(summary);
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.display.darkmode;
|
||||
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.PowerManager;
|
||||
import androidx.preference.DropDownPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
/**
|
||||
* Controller for the dark ui option dropdown
|
||||
*/
|
||||
public class DarkModeScheduleSelectorController extends BasePreferenceController
|
||||
implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
private final UiModeManager mUiModeManager;
|
||||
private PowerManager mPowerManager;
|
||||
private DropDownPreference mPreference;
|
||||
private String mCurrentMode;
|
||||
|
||||
public DarkModeScheduleSelectorController(Context context, String key) {
|
||||
super(context, key);
|
||||
mUiModeManager = context.getSystemService(UiModeManager.class);
|
||||
mPowerManager = context.getSystemService(PowerManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
|
||||
mPreference = screen.findPreference(getPreferenceKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return BasePreferenceController.AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void updateState(Preference preference) {
|
||||
final boolean batterySaver = mPowerManager.isPowerSaveMode();
|
||||
mPreference.setEnabled(!batterySaver);
|
||||
mCurrentMode =
|
||||
mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_AUTO
|
||||
? mContext.getString(R.string.dark_ui_auto_mode_auto)
|
||||
: mContext.getString(R.string.dark_ui_auto_mode_never);
|
||||
mPreference.setValue(mCurrentMode);
|
||||
}
|
||||
@Override
|
||||
public final boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
String newMode = (String) newValue;
|
||||
if (newMode == mCurrentMode) {
|
||||
return false;
|
||||
}
|
||||
mCurrentMode = newMode;
|
||||
if (mCurrentMode == mContext.getString(R.string.dark_ui_auto_mode_never)) {
|
||||
boolean active = (mContext.getResources().getConfiguration().uiMode
|
||||
& Configuration.UI_MODE_NIGHT_YES) != 0;
|
||||
int mode = active ? UiModeManager.MODE_NIGHT_YES
|
||||
: UiModeManager.MODE_NIGHT_NO;
|
||||
mUiModeManager.setNightMode(mode);
|
||||
|
||||
} else if (mCurrentMode ==
|
||||
mContext.getString(R.string.dark_ui_auto_mode_auto)) {
|
||||
mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_AUTO);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.display.darkmode;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
|
||||
/**
|
||||
* Settings screen for Dark UI Mode
|
||||
*/
|
||||
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
||||
public class DarkModeSettingsFragment extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "DarkModeSettingsFragment";
|
||||
private DarkModeObserver mContentObserver;
|
||||
private Runnable mCallback = () -> {
|
||||
updatePreferenceStates();
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final Context context = getContext();
|
||||
mContentObserver = new DarkModeObserver(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
// Listen for changes only while visible.
|
||||
mContentObserver.subscribe(mCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
// Stop listening for state changes.
|
||||
mContentObserver.unsubscribe();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.dark_mode_settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHelpResource() {
|
||||
return R.string.help_url_dark_theme;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.DARK_UI_SETTINGS;
|
||||
}
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider();
|
||||
}
|
@@ -55,8 +55,6 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
|
||||
TextView mBatteryPercentText;
|
||||
@VisibleForTesting
|
||||
TextView mSummary1;
|
||||
@VisibleForTesting
|
||||
TextView mSummary2;
|
||||
|
||||
private Activity mActivity;
|
||||
private PreferenceFragmentCompat mHost;
|
||||
@@ -90,7 +88,6 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
|
||||
.findViewById(R.id.battery_header_icon);
|
||||
mBatteryPercentText = mBatteryLayoutPref.findViewById(R.id.battery_percent);
|
||||
mSummary1 = mBatteryLayoutPref.findViewById(R.id.summary1);
|
||||
mSummary2 = mBatteryLayoutPref.findViewById(R.id.summary2);
|
||||
|
||||
quickUpdateHeaderPreference();
|
||||
}
|
||||
@@ -115,9 +112,6 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
|
||||
} else {
|
||||
mSummary1.setText(info.remainingLabel);
|
||||
}
|
||||
// Clear this just to be sure we don't get UI jank on re-entering this view from another
|
||||
// activity.
|
||||
mSummary2.setText("");
|
||||
|
||||
mBatteryMeterView.setBatteryLevel(info.batteryLevel);
|
||||
mBatteryMeterView.setCharging(!info.discharging);
|
||||
|
@@ -117,6 +117,13 @@ public class BatteryMeterView extends ImageView {
|
||||
.getDimensionPixelSize(R.dimen.battery_meter_height);
|
||||
}
|
||||
|
||||
public BatteryMeterDrawable(Context context, int frameColor, int width, int height) {
|
||||
super(context, frameColor);
|
||||
|
||||
mIntrinsicWidth = width;
|
||||
mIntrinsicHeight = height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
return mIntrinsicWidth;
|
||||
|
@@ -19,7 +19,6 @@ package com.android.settings.fuelgauge;
|
||||
import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
@@ -27,7 +26,6 @@ import android.os.BatteryStats;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.Global;
|
||||
import android.text.format.Formatter;
|
||||
import android.view.Menu;
|
||||
@@ -162,7 +160,6 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
|
||||
final TextView percentRemaining =
|
||||
mBatteryLayoutPref.findViewById(R.id.battery_percent);
|
||||
final TextView summary1 = mBatteryLayoutPref.findViewById(R.id.summary1);
|
||||
final TextView summary2 = mBatteryLayoutPref.findViewById(R.id.summary2);
|
||||
BatteryInfo oldInfo = batteryInfos.get(0);
|
||||
BatteryInfo newInfo = batteryInfos.get(1);
|
||||
percentRemaining.setText(Utils.formatPercentage(oldInfo.batteryLevel));
|
||||
@@ -170,14 +167,13 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
|
||||
// set the text to the old estimate (copied from battery info). Note that this
|
||||
// can sometimes say 0 time remaining because battery stats requires the phone
|
||||
// be unplugged for a period of time before being willing ot make an estimate.
|
||||
summary1.setText(mPowerFeatureProvider.getOldEstimateDebugString(
|
||||
final String OldEstimateString = mPowerFeatureProvider.getOldEstimateDebugString(
|
||||
Formatter.formatShortElapsedTime(getContext(),
|
||||
PowerUtil.convertUsToMs(oldInfo.remainingTimeUs))));
|
||||
|
||||
// for this one we can just set the string directly
|
||||
summary2.setText(mPowerFeatureProvider.getEnhancedEstimateDebugString(
|
||||
PowerUtil.convertUsToMs(oldInfo.remainingTimeUs)));
|
||||
final String NewEstimateString = mPowerFeatureProvider.getEnhancedEstimateDebugString(
|
||||
Formatter.formatShortElapsedTime(getContext(),
|
||||
PowerUtil.convertUsToMs(newInfo.remainingTimeUs))));
|
||||
PowerUtil.convertUsToMs(newInfo.remainingTimeUs)));
|
||||
summary1.setText(OldEstimateString + "\n" + NewEstimateString);
|
||||
|
||||
batteryView.setBatteryLevel(oldInfo.batteryLevel);
|
||||
batteryView.setCharging(!oldInfo.discharging);
|
||||
|
@@ -33,6 +33,7 @@ import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.accounts.AvatarViewMixin;
|
||||
import com.android.settings.core.HideNonSystemOverlayMixin;
|
||||
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
|
||||
@@ -54,8 +55,8 @@ public class SettingsHomepageActivity extends FragmentActivity {
|
||||
.initSearchToolbar(this /* activity */, toolbar, SettingsEnums.SETTINGS_HOMEPAGE);
|
||||
|
||||
final ImageView avatarView = findViewById(R.id.account_avatar);
|
||||
final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(this, avatarView);
|
||||
getLifecycle().addObserver(avatarViewMixin);
|
||||
getLifecycle().addObserver(new AvatarViewMixin(this, avatarView));
|
||||
getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
|
||||
|
||||
if (!getSystemService(ActivityManager.class).isLowRamDevice()) {
|
||||
// Only allow contextual feature on high ram devices.
|
||||
|
@@ -37,12 +37,11 @@ import com.android.settings.homepage.contextualcards.logging.ContextualCardLogUt
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
import com.android.settingslib.utils.AsyncLoaderCompat;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
@@ -56,7 +55,6 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
|
||||
private static final String TAG = "ContextualCardLoader";
|
||||
private static final long ELIGIBILITY_CHECKER_TIMEOUT_MS = 250;
|
||||
|
||||
private final ExecutorService mExecutorService;
|
||||
private final ContentObserver mObserver = new ContentObserver(
|
||||
new Handler(Looper.getMainLooper())) {
|
||||
@Override
|
||||
@@ -76,7 +74,6 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
|
||||
ContextualCardLoader(Context context) {
|
||||
super(context);
|
||||
mContext = context.getApplicationContext();
|
||||
mExecutorService = Executors.newCachedThreadPool();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -163,8 +160,8 @@ public class ContextualCardLoader extends AsyncLoaderCompat<List<ContextualCard>
|
||||
final List<Future<ContextualCard>> eligibleCards = new ArrayList<>();
|
||||
|
||||
for (ContextualCard card : candidates) {
|
||||
final EligibleCardChecker future = new EligibleCardChecker(mContext, card);
|
||||
eligibleCards.add(mExecutorService.submit(future));
|
||||
final EligibleCardChecker checker = new EligibleCardChecker(mContext, card);
|
||||
eligibleCards.add(ThreadUtils.postOnBackgroundThread(checker));
|
||||
}
|
||||
// Collect future and eligible cards
|
||||
for (Future<ContextualCard> cardFuture : eligibleCards) {
|
||||
|
@@ -78,6 +78,12 @@ public class SettingsContextualCardProvider extends ContextualCardProvider {
|
||||
.setCardName(CustomSliceRegistry.FACE_ENROLL_SLICE_URI.toString())
|
||||
.setCardCategory(ContextualCard.Category.DEFAULT)
|
||||
.build();
|
||||
final ContextualCard darkThemeCard =
|
||||
ContextualCard.newBuilder()
|
||||
.setSliceUri(CustomSliceRegistry.DARK_THEME_SLICE_URI.toString())
|
||||
.setCardName(CustomSliceRegistry.DARK_THEME_SLICE_URI.toString())
|
||||
.setCardCategory(ContextualCard.Category.IMPORTANT)
|
||||
.build();
|
||||
final ContextualCardList cards = ContextualCardList.newBuilder()
|
||||
.addCard(wifiCard)
|
||||
.addCard(connectedDeviceCard)
|
||||
@@ -86,6 +92,7 @@ public class SettingsContextualCardProvider extends ContextualCardProvider {
|
||||
.addCard(notificationChannelCard)
|
||||
.addCard(contextualAdaptiveSleepCard)
|
||||
.addCard(contextualFaceSettingsCard)
|
||||
.addCard(darkThemeCard)
|
||||
.build();
|
||||
|
||||
return cards;
|
||||
|
@@ -23,13 +23,12 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.homepage.contextualcards.ContextualCard;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
@@ -42,7 +41,6 @@ public class ConditionManager {
|
||||
|
||||
private static final long DISPLAYABLE_CHECKER_TIMEOUT_MS = 20;
|
||||
|
||||
private final ExecutorService mExecutorService;
|
||||
private final Context mAppContext;
|
||||
private final ConditionListener mListener;
|
||||
|
||||
@@ -50,7 +48,6 @@ public class ConditionManager {
|
||||
|
||||
public ConditionManager(Context context, ConditionListener listener) {
|
||||
mAppContext = context.getApplicationContext();
|
||||
mExecutorService = Executors.newCachedThreadPool();
|
||||
mCardControllers = new ArrayList<>();
|
||||
mListener = listener;
|
||||
initCandidates();
|
||||
@@ -64,8 +61,8 @@ public class ConditionManager {
|
||||
final List<Future<ContextualCard>> displayableCards = new ArrayList<>();
|
||||
// Check displayable future
|
||||
for (ConditionalCardController card : mCardControllers) {
|
||||
final DisplayableChecker future = new DisplayableChecker(getController(card.getId()));
|
||||
displayableCards.add(mExecutorService.submit(future));
|
||||
final DisplayableChecker checker = new DisplayableChecker(getController(card.getId()));
|
||||
displayableCards.add(ThreadUtils.postOnBackgroundThread(checker));
|
||||
}
|
||||
// Collect future and add displayable cards
|
||||
for (Future<ContextualCard> cardFuture : displayableCards) {
|
||||
|
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.settings.homepage.contextualcards.slices;
|
||||
|
||||
import static androidx.slice.builders.ListBuilder.ICON_IMAGE;
|
||||
|
||||
import static android.provider.Settings.Global.LOW_POWER_MODE;
|
||||
|
||||
import android.annotation.ColorInt;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.builders.ListBuilder;
|
||||
import androidx.slice.builders.SliceAction;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.slices.CustomSliceRegistry;
|
||||
import com.android.settings.slices.CustomSliceable;
|
||||
import com.android.settings.slices.SliceBackgroundWorker;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class DarkThemeSlice implements CustomSliceable {
|
||||
private static final String TAG = "DarkThemeSlice";
|
||||
private static final int BATTERY_LEVEL_THRESHOLD = 50;
|
||||
private static final int DELAY_TIME_EXECUTING_DARK_THEME = 200;
|
||||
|
||||
// Keep the slice even Dark theme mode changed when it is on HomePage
|
||||
@VisibleForTesting
|
||||
static boolean sKeepSliceShow;
|
||||
@VisibleForTesting
|
||||
static long sActiveUiSession = -1000;
|
||||
|
||||
private final Context mContext;
|
||||
private final UiModeManager mUiModeManager;
|
||||
private final PowerManager mPowerManager;
|
||||
|
||||
public DarkThemeSlice(Context context) {
|
||||
mContext = context;
|
||||
mUiModeManager = context.getSystemService(UiModeManager.class);
|
||||
mPowerManager = context.getSystemService(PowerManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice getSlice() {
|
||||
final long currentUiSession = FeatureFactory.getFactory(mContext)
|
||||
.getSlicesFeatureProvider().getUiSessionToken();
|
||||
if (currentUiSession != sActiveUiSession) {
|
||||
sActiveUiSession = currentUiSession;
|
||||
sKeepSliceShow = false;
|
||||
}
|
||||
// Dark theme slice will disappear when battery saver is ON.
|
||||
if (mPowerManager.isPowerSaveMode() || (!sKeepSliceShow && !isAvailable(mContext))) {
|
||||
return new ListBuilder(mContext, CustomSliceRegistry.DARK_THEME_SLICE_URI,
|
||||
ListBuilder.INFINITY)
|
||||
.setIsError(true)
|
||||
.build();
|
||||
}
|
||||
sKeepSliceShow = true;
|
||||
final PendingIntent toggleAction = getBroadcastIntent(mContext);
|
||||
@ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
|
||||
final IconCompat icon =
|
||||
IconCompat.createWithResource(mContext, R.drawable.dark_theme);
|
||||
return new ListBuilder(mContext, CustomSliceRegistry.DARK_THEME_SLICE_URI,
|
||||
ListBuilder.INFINITY)
|
||||
.setAccentColor(color)
|
||||
.addRow(new ListBuilder.RowBuilder()
|
||||
.setTitle(mContext.getText(R.string.dark_theme_slice_title))
|
||||
.setTitleItem(icon, ICON_IMAGE)
|
||||
.setSubtitle(mContext.getText(R.string.dark_theme_slice_subtitle))
|
||||
.setPrimaryAction(
|
||||
SliceAction.createToggle(toggleAction, null /* actionTitle */,
|
||||
isDarkThemeMode(mContext))))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri getUri() {
|
||||
return CustomSliceRegistry.DARK_THEME_SLICE_URI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotifyChange(Intent intent) {
|
||||
final boolean isChecked = intent.getBooleanExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE,
|
||||
false);
|
||||
// make toggle transition more smooth before dark theme takes effect
|
||||
new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||
mUiModeManager.setNightModeActivated(isChecked);
|
||||
}, DELAY_TIME_EXECUTING_DARK_THEME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getIntent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getBackgroundWorkerClass() {
|
||||
return DarkThemeWorker.class;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean isAvailable(Context context) {
|
||||
// checking dark theme mode.
|
||||
if (isDarkThemeMode(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// checking the current battery level
|
||||
final BatteryManager batteryManager = context.getSystemService(BatteryManager.class);
|
||||
final int level = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
|
||||
Log.d(TAG, "battery level=" + level);
|
||||
return level <= BATTERY_LEVEL_THRESHOLD;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean isDarkThemeMode(Context context) {
|
||||
final int currentNightMode =
|
||||
context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
return currentNightMode == Configuration.UI_MODE_NIGHT_YES;
|
||||
}
|
||||
|
||||
public static class DarkThemeWorker extends SliceBackgroundWorker<Void> {
|
||||
private final Context mContext;
|
||||
private final ContentObserver mContentObserver =
|
||||
new ContentObserver(new Handler(Looper.getMainLooper())) {
|
||||
@Override
|
||||
public void onChange(boolean bChanged) {
|
||||
if (mContext.getSystemService(PowerManager.class).isPowerSaveMode()) {
|
||||
notifySliceChange();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public DarkThemeWorker(Context context, Uri uri) {
|
||||
super(context, uri);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSlicePinned() {
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(LOW_POWER_MODE), false /* notifyForDescendants */,
|
||||
mContentObserver);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSliceUnpinned() {
|
||||
mContext.getContentResolver().unregisterContentObserver(mContentObserver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
}
|
||||
}
|
||||
}
|
@@ -20,8 +20,6 @@ import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||
import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
|
||||
|
||||
import static com.android.settings.notification.ChannelListPreferenceController.ARG_FROM_SETTINGS;
|
||||
|
||||
import android.app.Application;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationChannelGroup;
|
||||
@@ -62,13 +60,12 @@ import com.android.settings.slices.SliceBuilderUtils;
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
@@ -135,7 +132,6 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
};
|
||||
|
||||
protected final Context mContext;
|
||||
private final ExecutorService mExecutorService;
|
||||
@VisibleForTesting
|
||||
NotificationBackend mNotificationBackend;
|
||||
private NotificationBackend.AppRow mAppRow;
|
||||
@@ -145,7 +141,6 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
public NotificationChannelSlice(Context context) {
|
||||
mContext = context;
|
||||
mNotificationBackend = new NotificationBackend();
|
||||
mExecutorService = Executors.newCachedThreadPool();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -376,9 +371,9 @@ public class NotificationChannelSlice implements CustomSliceable {
|
||||
// Create tasks to get notification data for multi-channel packages.
|
||||
final List<Future<NotificationBackend.AppRow>> appRowTasks = new ArrayList<>();
|
||||
for (PackageInfo packageInfo : packageInfoList) {
|
||||
final NotificationMultiChannelAppRow future = new NotificationMultiChannelAppRow(
|
||||
final NotificationMultiChannelAppRow appRow = new NotificationMultiChannelAppRow(
|
||||
mContext, mNotificationBackend, packageInfo);
|
||||
appRowTasks.add(mExecutorService.submit(future));
|
||||
appRowTasks.add(ThreadUtils.postOnBackgroundThread(appRow));
|
||||
}
|
||||
|
||||
// Get the package which has sent at least ~10 notifications and not turn off channels.
|
||||
|
@@ -22,11 +22,8 @@ import android.os.Looper;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.telephony.data.ApnSetting;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.android.settings.network.MobileDataContentObserver;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
@@ -41,14 +38,14 @@ public class MmsMessagePreferenceController extends TelephonyTogglePreferenceCon
|
||||
private TelephonyManager mTelephonyManager;
|
||||
private SubscriptionManager mSubscriptionManager;
|
||||
private MobileDataContentObserver mMobileDataContentObserver;
|
||||
private SwitchPreference mPreference;
|
||||
private PreferenceScreen mScreen;
|
||||
|
||||
public MmsMessagePreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
|
||||
mMobileDataContentObserver = new MobileDataContentObserver(
|
||||
new Handler(Looper.getMainLooper()));
|
||||
mMobileDataContentObserver.setOnMobileDataChangedListener(()->updateState(mPreference));
|
||||
mMobileDataContentObserver.setOnMobileDataChangedListener(()->refreshPreference());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,15 +76,9 @@ public class MmsMessagePreferenceController extends TelephonyTogglePreferenceCon
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mPreference = screen.findPreference(getPreferenceKey());
|
||||
mScreen = screen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
preference.setVisible(isAvailable());
|
||||
((SwitchPreference) preference).setChecked(isChecked());
|
||||
}
|
||||
|
||||
public void init(int subId) {
|
||||
mSubId = subId;
|
||||
@@ -104,4 +95,10 @@ public class MmsMessagePreferenceController extends TelephonyTogglePreferenceCon
|
||||
public boolean isChecked() {
|
||||
return mTelephonyManager.isDataEnabledForApn(ApnSetting.TYPE_MMS);
|
||||
}
|
||||
|
||||
private void refreshPreference() {
|
||||
if (mScreen != null) {
|
||||
super.displayPreference(mScreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -228,16 +228,23 @@ public class MobileNetworkUtils {
|
||||
final String currentCountry = tm.getNetworkCountryIso().toLowerCase();
|
||||
final String supportedCountries =
|
||||
Settings.Global.getString(cr, Settings.Global.EUICC_SUPPORTED_COUNTRIES);
|
||||
final String unsupportedCountries =
|
||||
Settings.Global.getString(cr, Settings.Global.EUICC_UNSUPPORTED_COUNTRIES);
|
||||
|
||||
boolean inEsimSupportedCountries = false;
|
||||
if (TextUtils.isEmpty(currentCountry)) {
|
||||
inEsimSupportedCountries = true;
|
||||
} else if (!TextUtils.isEmpty(supportedCountries)) {
|
||||
final List<String> supportedCountryList =
|
||||
Arrays.asList(TextUtils.split(supportedCountries.toLowerCase(), ","));
|
||||
if (supportedCountryList.contains(currentCountry)) {
|
||||
inEsimSupportedCountries = true;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(supportedCountries)) {
|
||||
// White list is empty, use blacklist.
|
||||
Log.d(TAG, "Using blacklist unsupportedCountries=" + unsupportedCountries);
|
||||
inEsimSupportedCountries = !isEsimUnsupportedCountry(currentCountry,
|
||||
unsupportedCountries);
|
||||
} else {
|
||||
Log.d(TAG, "Using whitelist supportedCountries=" + supportedCountries);
|
||||
inEsimSupportedCountries = isEsimSupportedCountry(currentCountry, supportedCountries);
|
||||
}
|
||||
|
||||
Log.d(TAG, "inEsimSupportedCountries=" + inEsimSupportedCountries);
|
||||
|
||||
final boolean esimIgnoredDevice =
|
||||
Arrays.asList(TextUtils.split(SystemProperties.get(KEY_ESIM_CID_IGNORE, ""), ","))
|
||||
.contains(SystemProperties.get(KEY_CID, null));
|
||||
@@ -613,4 +620,24 @@ public class MobileNetworkUtils {
|
||||
}
|
||||
return tm.getNetworkOperatorName();
|
||||
}
|
||||
|
||||
private static boolean isEsimSupportedCountry(String country, String countriesListString) {
|
||||
if (TextUtils.isEmpty(country)) {
|
||||
return true;
|
||||
} else if (TextUtils.isEmpty(countriesListString)) {
|
||||
return false;
|
||||
}
|
||||
final List<String> supportedCountries =
|
||||
Arrays.asList(TextUtils.split(countriesListString.toLowerCase(), ","));
|
||||
return supportedCountries.contains(country);
|
||||
}
|
||||
|
||||
private static boolean isEsimUnsupportedCountry(String country, String countriesListString) {
|
||||
if (TextUtils.isEmpty(country) || TextUtils.isEmpty(countriesListString)) {
|
||||
return false;
|
||||
}
|
||||
final List<String> unsupportedCountries =
|
||||
Arrays.asList(TextUtils.split(countriesListString.toLowerCase(), ","));
|
||||
return unsupportedCountries.contains(country);
|
||||
}
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ import com.android.settings.R;
|
||||
import com.android.settings.accounts.AccountFeatureProvider;
|
||||
import com.android.settings.applications.ApplicationFeatureProvider;
|
||||
import com.android.settings.aware.AwareFeatureProvider;
|
||||
import com.android.settings.biometrics.face.FaceFeatureProvider;
|
||||
import com.android.settings.bluetooth.BluetoothFeatureProvider;
|
||||
import com.android.settings.dashboard.DashboardFeatureProvider;
|
||||
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
|
||||
@@ -133,6 +134,8 @@ public abstract class FeatureFactory {
|
||||
|
||||
public abstract AwareFeatureProvider getAwareFeatureProvider();
|
||||
|
||||
public abstract FaceFeatureProvider getFaceFeatureProvider();
|
||||
|
||||
public static final class FactoryNotFoundException extends RuntimeException {
|
||||
public FactoryNotFoundException(Throwable throwable) {
|
||||
super("Unable to create factory. Did you misconfigure Proguard?", throwable);
|
||||
|
@@ -30,6 +30,8 @@ import com.android.settings.applications.ApplicationFeatureProvider;
|
||||
import com.android.settings.applications.ApplicationFeatureProviderImpl;
|
||||
import com.android.settings.aware.AwareFeatureProvider;
|
||||
import com.android.settings.aware.AwareFeatureProviderImpl;
|
||||
import com.android.settings.biometrics.face.FaceFeatureProvider;
|
||||
import com.android.settings.biometrics.face.FaceFeatureProviderImpl;
|
||||
import com.android.settings.bluetooth.BluetoothFeatureProvider;
|
||||
import com.android.settings.bluetooth.BluetoothFeatureProviderImpl;
|
||||
import com.android.settings.connecteddevice.dock.DockUpdaterFeatureProviderImpl;
|
||||
@@ -84,6 +86,7 @@ public class FeatureFactoryImpl extends FeatureFactory {
|
||||
private ContextualCardFeatureProvider mContextualCardFeatureProvider;
|
||||
private BluetoothFeatureProvider mBluetoothFeatureProvider;
|
||||
private AwareFeatureProvider mAwareFeatureProvider;
|
||||
private FaceFeatureProvider mFaceFeatureProvider;
|
||||
|
||||
@Override
|
||||
public SupportFeatureProvider getSupportFeatureProvider(Context context) {
|
||||
@@ -255,4 +258,12 @@ public class FeatureFactoryImpl extends FeatureFactory {
|
||||
}
|
||||
return mAwareFeatureProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaceFeatureProvider getFaceFeatureProvider() {
|
||||
if (mFaceFeatureProvider == null) {
|
||||
mFaceFeatureProvider = new FaceFeatureProviderImpl();
|
||||
}
|
||||
return mFaceFeatureProvider;
|
||||
}
|
||||
}
|
||||
|
@@ -32,6 +32,7 @@ import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.HideNonSystemOverlayMixin;
|
||||
|
||||
/**
|
||||
* Dialog Activity to host Settings Slices.
|
||||
@@ -62,6 +63,7 @@ public class SettingsPanelActivity extends FragmentActivity {
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
createOrUpdatePanel(true /* shouldForceCreation */);
|
||||
getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -1,243 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.privacy;
|
||||
|
||||
import static android.Manifest.permission_group.CAMERA;
|
||||
import static android.Manifest.permission_group.LOCATION;
|
||||
import static android.Manifest.permission_group.MICROPHONE;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.DAYS;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.permission.PermissionControllerManager;
|
||||
import android.permission.RuntimePermissionUsageInfo;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.Utils;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnCreate;
|
||||
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.widget.BarChartInfo;
|
||||
import com.android.settingslib.widget.BarChartPreference;
|
||||
import com.android.settingslib.widget.BarViewInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class PermissionBarChartPreferenceController extends BasePreferenceController implements
|
||||
PermissionControllerManager.OnPermissionUsageResultCallback, LifecycleObserver, OnCreate,
|
||||
OnStart, OnSaveInstanceState {
|
||||
|
||||
private static final String TAG = "BarChartPreferenceCtl";
|
||||
private static final String KEY_PERMISSION_USAGE = "usage_infos";
|
||||
|
||||
@VisibleForTesting
|
||||
List<RuntimePermissionUsageInfo> mOldUsageInfos;
|
||||
private PackageManager mPackageManager;
|
||||
private PrivacyDashboardFragment mParent;
|
||||
private BarChartPreference mBarChartPreference;
|
||||
|
||||
public PermissionBarChartPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mOldUsageInfos = new ArrayList<>();
|
||||
mPackageManager = context.getPackageManager();
|
||||
}
|
||||
|
||||
public void setFragment(PrivacyDashboardFragment fragment) {
|
||||
mParent = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
if (savedInstanceState != null) {
|
||||
mOldUsageInfos = savedInstanceState.getParcelableArrayList(KEY_PERMISSION_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putParcelableList(KEY_PERMISSION_USAGE, mOldUsageInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return UNSUPPORTED_ON_DEVICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mBarChartPreference = screen.findPreference(getPreferenceKey());
|
||||
|
||||
final BarChartInfo info = new BarChartInfo.Builder()
|
||||
.setTitle(R.string.permission_bar_chart_title)
|
||||
.setDetails(R.string.permission_bar_chart_details)
|
||||
.setEmptyText(R.string.permission_bar_chart_empty_text)
|
||||
.setDetailsOnClickListener((View v) -> {
|
||||
final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
|
||||
intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1));
|
||||
mContext.startActivity(intent);
|
||||
})
|
||||
.build();
|
||||
|
||||
mBarChartPreference.initializeBarChart(info);
|
||||
if (!mOldUsageInfos.isEmpty()) {
|
||||
mBarChartPreference.setBarViewInfos(createBarViews(mOldUsageInfos));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
if (!isAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't hide chart when we have existing data.
|
||||
mBarChartPreference.updateLoadingState(mOldUsageInfos.isEmpty() /* isLoading */);
|
||||
// But we still need to hint user with progress bar that we are updating new usage data.
|
||||
mParent.setLoadingEnabled(true /* enabled */);
|
||||
retrievePermissionUsageData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPermissionUsageResult(@NonNull List<RuntimePermissionUsageInfo> usageInfos) {
|
||||
usageInfos.sort((x, y) -> {
|
||||
int usageDiff = y.getAppAccessCount() - x.getAppAccessCount();
|
||||
if (usageDiff != 0) {
|
||||
return usageDiff;
|
||||
}
|
||||
String xName = x.getName();
|
||||
String yName = y.getName();
|
||||
if (xName.equals(LOCATION)) {
|
||||
return -1;
|
||||
} else if (yName.equals(LOCATION)) {
|
||||
return 1;
|
||||
} else if (xName.equals(MICROPHONE)) {
|
||||
return -1;
|
||||
} else if (yName.equals(MICROPHONE)) {
|
||||
return 1;
|
||||
} else if (xName.equals(CAMERA)) {
|
||||
return -1;
|
||||
} else if (yName.equals(CAMERA)) {
|
||||
return 1;
|
||||
}
|
||||
return x.getName().compareTo(y.getName());
|
||||
});
|
||||
|
||||
// If the result is different, we need to update bar views.
|
||||
if (!areSamePermissionGroups(usageInfos)) {
|
||||
mBarChartPreference.setBarViewInfos(createBarViews(usageInfos));
|
||||
mOldUsageInfos = usageInfos;
|
||||
}
|
||||
|
||||
mBarChartPreference.updateLoadingState(false /* isLoading */);
|
||||
mParent.setLoadingEnabled(false /* enabled */);
|
||||
}
|
||||
|
||||
private void retrievePermissionUsageData() {
|
||||
mContext.getSystemService(PermissionControllerManager.class).getPermissionUsages(
|
||||
false /* countSystem */, (int) DAYS.toMillis(1),
|
||||
mContext.getMainExecutor() /* executor */, this /* callback */);
|
||||
}
|
||||
|
||||
private BarViewInfo[] createBarViews(List<RuntimePermissionUsageInfo> usageInfos) {
|
||||
if (usageInfos.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final BarViewInfo[] barViewInfos = new BarViewInfo[
|
||||
Math.min(BarChartPreference.MAXIMUM_BAR_VIEWS, usageInfos.size())];
|
||||
|
||||
for (int index = 0; index < barViewInfos.length; index++) {
|
||||
final RuntimePermissionUsageInfo permissionGroupInfo = usageInfos.get(index);
|
||||
final int count = permissionGroupInfo.getAppAccessCount();
|
||||
final CharSequence permLabel = getPermissionGroupLabel(permissionGroupInfo.getName());
|
||||
|
||||
barViewInfos[index] = new BarViewInfo(
|
||||
getPermissionGroupIcon(permissionGroupInfo.getName()), count, permLabel,
|
||||
mContext.getResources().getQuantityString(R.plurals.permission_bar_chart_label,
|
||||
count, count), permLabel);
|
||||
|
||||
// Set the click listener for each bar view.
|
||||
// The listener will navigate user to permission usage app.
|
||||
barViewInfos[index].setClickListener((View v) -> {
|
||||
final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
|
||||
intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permissionGroupInfo.getName());
|
||||
intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1));
|
||||
mContext.startActivity(intent);
|
||||
});
|
||||
}
|
||||
|
||||
return barViewInfos;
|
||||
}
|
||||
|
||||
private Drawable getPermissionGroupIcon(String permissionGroup) {
|
||||
Drawable icon = null;
|
||||
try {
|
||||
icon = mPackageManager.getPermissionGroupInfo(permissionGroup, 0)
|
||||
.loadIcon(mPackageManager);
|
||||
icon.setTintList(Utils.getColorAttr(mContext, android.R.attr.textColorSecondary));
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.w(TAG, "Cannot find group icon for " + permissionGroup, e);
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
private CharSequence getPermissionGroupLabel(String permissionGroup) {
|
||||
CharSequence label = null;
|
||||
try {
|
||||
label = mPackageManager.getPermissionGroupInfo(permissionGroup, 0)
|
||||
.loadLabel(mPackageManager);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.w(TAG, "Cannot find group label for " + permissionGroup, e);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
private boolean areSamePermissionGroups(List<RuntimePermissionUsageInfo> newUsageInfos) {
|
||||
if (newUsageInfos.size() != mOldUsageInfos.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int index = 0; index < newUsageInfos.size(); index++) {
|
||||
final RuntimePermissionUsageInfo newInfo = newUsageInfos.get(index);
|
||||
final RuntimePermissionUsageInfo oldInfo = mOldUsageInfos.get(index);
|
||||
|
||||
if (!newInfo.getName().equals(oldInfo.getName()) ||
|
||||
newInfo.getAppAccessCount() != oldInfo.getAppAccessCount()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -18,14 +18,12 @@ package com.android.settings.privacy;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.notification.LockScreenNotificationPreferenceController;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
@@ -75,34 +73,6 @@ public class PrivacyDashboardFragment extends DashboardFragment {
|
||||
return buildPreferenceControllers(context, getSettingsLifecycle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
use(PermissionBarChartPreferenceController.class).setFragment(this /* fragment */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
Utils.setActionBarShadowAnimation(getActivity(), getSettingsLifecycle(), getListView());
|
||||
initLoadingBar();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void initLoadingBar() {
|
||||
mProgressHeader = setPinnedHeaderView(R.layout.progress_header);
|
||||
mProgressAnimation = mProgressHeader.findViewById(R.id.progress_bar_animation);
|
||||
setLoadingEnabled(false);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setLoadingEnabled(boolean enabled) {
|
||||
if (mProgressHeader != null && mProgressAnimation != null) {
|
||||
mProgressHeader.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
|
||||
mProgressAnimation.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<AbstractPreferenceController> buildPreferenceControllers(
|
||||
Context context, Lifecycle lifecycle) {
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
|
@@ -37,6 +37,7 @@ import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;
|
||||
import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlice;
|
||||
import com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice;
|
||||
import com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice;
|
||||
import com.android.settings.homepage.contextualcards.slices.DarkThemeSlice;
|
||||
import com.android.settings.homepage.contextualcards.slices.FaceSetupSlice;
|
||||
import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
|
||||
import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice;
|
||||
@@ -342,6 +343,16 @@ public class CustomSliceRegistry {
|
||||
.appendPath("media_output_indicator")
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Backing Uri for the Dark theme Slice.
|
||||
*/
|
||||
public static final Uri DARK_THEME_SLICE_URI = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
|
||||
.appendPath("dark_theme")
|
||||
.build();
|
||||
|
||||
@VisibleForTesting
|
||||
static final Map<Uri, Class<? extends CustomSliceable>> sUriToSlice;
|
||||
|
||||
@@ -367,6 +378,7 @@ public class CustomSliceRegistry {
|
||||
sUriToSlice.put(NOTIFICATION_CHANNEL_SLICE_URI, NotificationChannelSlice.class);
|
||||
sUriToSlice.put(STORAGE_SLICE_URI, StorageSlice.class);
|
||||
sUriToSlice.put(WIFI_SLICE_URI, WifiSlice.class);
|
||||
sUriToSlice.put(DARK_THEME_SLICE_URI, DarkThemeSlice.class);
|
||||
}
|
||||
|
||||
public static Class<? extends CustomSliceable> getSliceClassByUri(Uri uri) {
|
||||
|
@@ -95,7 +95,7 @@ public interface CustomSliceable extends Sliceable {
|
||||
.setData(getUri())
|
||||
.setClass(context, SliceBroadcastReceiver.class);
|
||||
return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -175,7 +175,7 @@ public class SliceBuilderUtils {
|
||||
.putExtra(EXTRA_SLICE_KEY, data.getKey())
|
||||
.putExtra(EXTRA_SLICE_PLATFORM_DEFINED, data.isPlatformDefined());
|
||||
return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -310,7 +310,7 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
|
||||
mHandler.sendEmptyMessageDelayed(MESSAGE_STOP_SCAN_WIFI_LIST, DELAY_TIME_STOP_SCAN_MS);
|
||||
|
||||
if (mFilterWifiTracker == null) {
|
||||
mFilterWifiTracker = new FilterWifiTracker(getActivity(), getSettingsLifecycle());
|
||||
mFilterWifiTracker = new FilterWifiTracker(getContext(), getSettingsLifecycle());
|
||||
}
|
||||
mFilterWifiTracker.onResume();
|
||||
}
|
||||
@@ -476,11 +476,13 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
|
||||
private final class FilterWifiTracker {
|
||||
private final List<String> mAccessPointKeys;
|
||||
private final WifiTracker mWifiTracker;
|
||||
private final Context mContext;
|
||||
|
||||
public FilterWifiTracker(Context context, Lifecycle lifecycle) {
|
||||
mWifiTracker = WifiTrackerFactory.create(context, mWifiListener,
|
||||
lifecycle, /* includeSaved */ true, /* includeScans */ true);
|
||||
mAccessPointKeys = new ArrayList<>();
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -489,7 +491,7 @@ public class NetworkRequestDialogFragment extends InstrumentedDialogFragment imp
|
||||
*/
|
||||
public void updateKeys(List<ScanResult> scanResults) {
|
||||
for (ScanResult scanResult : scanResults) {
|
||||
final String key = AccessPoint.getKey(scanResult);
|
||||
final String key = AccessPoint.getKey(mContext, scanResult);
|
||||
if (!mAccessPointKeys.contains(key)) {
|
||||
mAccessPointKeys.add(key);
|
||||
}
|
||||
|
@@ -583,35 +583,6 @@ public class WifiConfigController implements TextWatcher,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special handling for WPA2/WPA3 and OWE in Transition mode: The key
|
||||
* SECURITY_PSK_SAE_TRANSITION and SECURITY_OWE_TRANSITION are pseudo keys which result by the
|
||||
* scan results, but never appears in the saved networks.
|
||||
* A saved network is either WPA3 for supporting devices or WPA2 for non-supporting devices,
|
||||
* or, OWE for supporting devices or Open for non-supporting devices.
|
||||
*
|
||||
* @param accessPointSecurity Access point current security type
|
||||
* @return Converted security type (if required)
|
||||
*/
|
||||
private int convertSecurityTypeForMatching(int accessPointSecurity) {
|
||||
if (accessPointSecurity == AccessPoint.SECURITY_PSK_SAE_TRANSITION) {
|
||||
if (mWifiManager.isWpa3SaeSupported()) {
|
||||
return AccessPoint.SECURITY_SAE;
|
||||
} else {
|
||||
return AccessPoint.SECURITY_PSK;
|
||||
}
|
||||
}
|
||||
if (accessPointSecurity == AccessPoint.SECURITY_OWE_TRANSITION) {
|
||||
if (mWifiManager.isEnhancedOpenSupported()) {
|
||||
return AccessPoint.SECURITY_OWE;
|
||||
} else {
|
||||
return AccessPoint.SECURITY_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return accessPointSecurity;
|
||||
}
|
||||
|
||||
public WifiConfiguration getConfig() {
|
||||
if (mMode == WifiConfigUiBase.MODE_VIEW) {
|
||||
return null;
|
||||
@@ -634,8 +605,6 @@ public class WifiConfigController implements TextWatcher,
|
||||
|
||||
config.shared = mSharedCheckBox.isChecked();
|
||||
|
||||
mAccessPointSecurity = convertSecurityTypeForMatching(mAccessPointSecurity);
|
||||
|
||||
switch (mAccessPointSecurity) {
|
||||
case AccessPoint.SECURITY_NONE:
|
||||
config.allowedKeyManagement.set(KeyMgmt.NONE);
|
||||
@@ -960,8 +929,7 @@ public class WifiConfigController implements TextWatcher,
|
||||
|
||||
private void showSecurityFields(boolean refreshEapMethods, boolean refreshCertificates) {
|
||||
if (mAccessPointSecurity == AccessPoint.SECURITY_NONE ||
|
||||
mAccessPointSecurity == AccessPoint.SECURITY_OWE ||
|
||||
mAccessPointSecurity == AccessPoint.SECURITY_OWE_TRANSITION) {
|
||||
mAccessPointSecurity == AccessPoint.SECURITY_OWE) {
|
||||
mView.findViewById(R.id.security_fields).setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
@@ -494,9 +494,7 @@ public class WifiSettings extends RestrictedSettingsFragment
|
||||
if (isSavedNetwork) {
|
||||
connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
|
||||
} else if ((mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) ||
|
||||
(mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE) ||
|
||||
(mSelectedAccessPoint.getSecurity()
|
||||
== AccessPoint.SECURITY_OWE_TRANSITION)) {
|
||||
(mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_OWE)) {
|
||||
/** Bypass dialog for unsecured networks */
|
||||
mSelectedAccessPoint.generateOpenNetworkConfig();
|
||||
connect(mSelectedAccessPoint.getConfig(), isSavedNetwork);
|
||||
@@ -750,8 +748,7 @@ public class WifiSettings extends RestrictedSettingsFragment
|
||||
preference.setOrder(index);
|
||||
if (mOpenSsid != null && mOpenSsid.equals(accessPoint.getSsidStr())
|
||||
&& (accessPoint.getSecurity() != AccessPoint.SECURITY_NONE &&
|
||||
accessPoint.getSecurity() != AccessPoint.SECURITY_OWE &&
|
||||
accessPoint.getSecurity() != AccessPoint.SECURITY_OWE_TRANSITION)) {
|
||||
accessPoint.getSecurity() != AccessPoint.SECURITY_OWE)) {
|
||||
if (!accessPoint.isSaved() || isDisabledByWrongPassword(accessPoint)) {
|
||||
onPreferenceTreeClick(preference);
|
||||
mOpenSsid = null;
|
||||
|
@@ -268,8 +268,7 @@ public class WifiUtils {
|
||||
if (accessPoint.isOsuProvider()) {
|
||||
return CONNECT_TYPE_OSU_PROVISION;
|
||||
} else if ((accessPoint.getSecurity() == AccessPoint.SECURITY_NONE) ||
|
||||
(accessPoint.getSecurity() == AccessPoint.SECURITY_OWE) ||
|
||||
(accessPoint.getSecurity() == AccessPoint.SECURITY_OWE_TRANSITION)) {
|
||||
(accessPoint.getSecurity() == AccessPoint.SECURITY_OWE)) {
|
||||
return CONNECT_TYPE_OPEN_NETWORK;
|
||||
} else if (accessPoint.isSaved() && config != null
|
||||
&& config.getNetworkSelectionStatus() != null
|
||||
|
@@ -206,7 +206,7 @@ public class WifiDppUtils {
|
||||
setConfiguratorIntentExtra(intent, wifiManager, wifiConfiguration);
|
||||
|
||||
// For a transition mode Wi-Fi AP, creates a QR code that's compatible with more devices
|
||||
if (accessPoint.getSecurity() == AccessPoint.SECURITY_PSK_SAE_TRANSITION) {
|
||||
if (accessPoint.isPskSaeTransitionMode()) {
|
||||
intent.putExtra(EXTRA_WIFI_SECURITY, WifiQrCode.SECURITY_WPA_PSK);
|
||||
}
|
||||
|
||||
@@ -406,7 +406,6 @@ public class WifiDppUtils {
|
||||
}
|
||||
break;
|
||||
case AccessPoint.SECURITY_PSK:
|
||||
case AccessPoint.SECURITY_PSK_SAE_TRANSITION:
|
||||
return true;
|
||||
default:
|
||||
}
|
||||
@@ -419,8 +418,6 @@ public class WifiDppUtils {
|
||||
case AccessPoint.SECURITY_PSK:
|
||||
case AccessPoint.SECURITY_WEP:
|
||||
case AccessPoint.SECURITY_NONE:
|
||||
case AccessPoint.SECURITY_PSK_SAE_TRANSITION:
|
||||
case AccessPoint.SECURITY_OWE_TRANSITION:
|
||||
return true;
|
||||
case AccessPoint.SECURITY_SAE:
|
||||
if (wifiManager.isWpa3SaeSupported()) {
|
||||
|
Reference in New Issue
Block a user