Snap for 4641295 from 6949175423 to pi-release
Change-Id: I7f62e2c3f112137791fdbd28bb3c9b97ca2e9f3b
This commit is contained in:
@@ -3786,8 +3786,8 @@
|
||||
<string name="disable_text">Disable</string>
|
||||
<!-- [CHAR LIMIT=25] Manage applications, individual application info screen, button label under Storage heading. Button to re-enable an existing application. -->
|
||||
<string name="enable_text">Enable</string>
|
||||
<!-- Manage applications, individual application info screen, button label under Storage heading. Button to clear all data associated with tis app (for exampel, remove all cached emails for an Email app) -->
|
||||
<string name="clear_user_data_text">Clear data</string>
|
||||
<!-- Manage applications, individual application info screen, button label under Storage heading. Button to clear all data associated with tis app (for example, remove all cached emails for an Email app) -->
|
||||
<string name="clear_user_data_text">Clear storage</string>
|
||||
<!-- Manage applications, restore updated system application to factory version -->
|
||||
<string name="app_factory_reset">Uninstall updates</string>
|
||||
<!-- Manage applications, individual application info screen, screen, message text under Launch by default heading. This is present if the app is set as a default for some actions. -->
|
||||
@@ -3883,12 +3883,8 @@
|
||||
<string name="app_not_found_dlg_title"></string>
|
||||
<!-- Manage applications, individual application dialog box message. Shown when the user somehow got into a state where it wants to manage some app that isn't found. -->
|
||||
<string name="app_not_found_dlg_text"> The app wasn\u2019t found in the list of installed apps.</string>
|
||||
<!-- Manage applications, individual application dialog box message. Shown when there was an error trying to clear the data. -->
|
||||
<string name="clear_data_failed">Couldn\u2019t clear app data.</string>
|
||||
<!-- Manage applications, title for dialog if clear data fails-->
|
||||
<string name="clear_failed_dlg_title">Clear data</string>
|
||||
<!-- Manage applications, text for dialog if clear data fails-->
|
||||
<string name="clear_failed_dlg_text">Couldn\u2019t clear data for app.</string>
|
||||
<string name="clear_failed_dlg_text">Couldn\u2019t clear storage for app.</string>
|
||||
<!-- Manage applications, individual application info screen, text that appears under the "Permissions" heading. This describes the permissions that the application has. -->
|
||||
<string name="security_settings_desc" product="tablet">This app can access the following on your tablet:</string>
|
||||
<!-- Manage applications, individual application info screen, text that appears under the "Permissions" heading. This describes the permissions that the application has. -->
|
||||
@@ -7549,10 +7545,10 @@
|
||||
<string name="zen_mode_alarms">Alarms</string>
|
||||
|
||||
<!-- [CHAR LIMIT=50] Zen mode settings: Media option -->
|
||||
<string name="zen_mode_media_system_other">Media</string>
|
||||
<string name="zen_mode_media">Media</string>
|
||||
|
||||
<!-- [CHAR LIMIT=120] Zen mode settings: Media secondary text explaining sounds include system feedback such as system tapping sounds, haptic feedback, etc. -->
|
||||
<string name="zen_mode_media_system_other_secondary_text">Includes system feedback like touch and charging sounds</string>
|
||||
<!-- [CHAR LIMIT=50] Zen mode settings: System option which includes sounds such as touch and charging sounds -->
|
||||
<string name="zen_mode_system">Touch and charging sounds</string>
|
||||
|
||||
<!-- [CHAR LIMIT=50] Zen mode settings: Reminders option -->
|
||||
<string name="zen_mode_reminders">Reminders</string>
|
||||
@@ -8633,8 +8629,11 @@
|
||||
<!-- Format for a summary describing the amount of data before the user is warned or limited [CHAR LIMIT=NONE] -->
|
||||
<string name="cell_warning_and_limit"><xliff:g name="amount" example="1 GB">%1$s</xliff:g> Data warning / <xliff:g name="amount" example="2 GB">%2$s</xliff:g> Data limit</string>
|
||||
|
||||
<!-- Title of button and screen for billing cycle preferences [CHAR LIMIT=30 -->
|
||||
<string name="billing_cycle">Billing cycle</string>
|
||||
<!-- Title of button and screen for billing cycle preferences [CHAR LIMIT=30] -->
|
||||
<string name="billing_cycle">Data warning & limit</string>
|
||||
|
||||
<!-- Title of button for application usage cycle preferences [CHAR LIMIT=30] -->
|
||||
<string name="app_usage_cycle">App data usage cycle</string>
|
||||
|
||||
<!-- Summary describing when the billing cycle for their phone carrier starts [CHAR LIMIT=NONE] -->
|
||||
<string name="billing_cycle_fragment_summary">Monthly on day <xliff:g name="day_of_month" example="17">%1$s</xliff:g></string>
|
||||
|
||||
@@ -14,17 +14,21 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:key="accessibility_settings_vibration_screen"
|
||||
android:title="@string/accessibility_vibration_settings_title">
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:key="accessibility_settings_vibration_screen"
|
||||
android:title="@string/accessibility_vibration_settings_title">
|
||||
|
||||
<Preference
|
||||
android:fragment="com.android.settings.accessibility.NotificationVibrationPreferenceFragment"
|
||||
android:key="notification_vibration_preference_screen"
|
||||
android:title="@string/accessibility_notification_vibration_title" />
|
||||
android:title="@string/accessibility_notification_vibration_title"
|
||||
app:controller="com.android.settings.accessibility.NotificationVibrationIntensityPreferenceController" />
|
||||
|
||||
<Preference
|
||||
android:fragment="com.android.settings.accessibility.TouchVibrationPreferenceFragment"
|
||||
android:key="touch_vibration_preference_screen"
|
||||
android:title="@string/accessibility_touch_vibration_title" />
|
||||
android:title="@string/accessibility_touch_vibration_title"
|
||||
app:controller="com.android.settings.accessibility.HapticFeedbackIntensityPreferenceController" />
|
||||
</PreferenceScreen>
|
||||
|
||||
@@ -23,6 +23,25 @@
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="dashboard_tile_placeholder"
|
||||
android:order="200"/>
|
||||
android:order="30"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="auto_sync_account_data"
|
||||
android:title="@string/auto_sync_account_title"
|
||||
android:summary="@string/auto_sync_account_summary"
|
||||
android:order="102"
|
||||
settings:allowDividerAbove="true"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="auto_sync_work_account_data"
|
||||
android:title="@string/account_settings_menu_auto_sync_work"
|
||||
android:summary="@string/auto_sync_account_summary"
|
||||
android:order="103"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="auto_sync_personal_account_data"
|
||||
android:title="@string/account_settings_menu_auto_sync_personal"
|
||||
android:summary="@string/auto_sync_account_summary"
|
||||
android:order="104"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
<Preference
|
||||
android:key="billing_cycle"
|
||||
android:title="@string/billing_cycle" />
|
||||
android:title="@string/app_usage_cycle" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="set_data_warning"
|
||||
|
||||
@@ -28,13 +28,15 @@
|
||||
android:key="saved_device_list"
|
||||
android:title="@string/connected_device_saved_title"/>
|
||||
|
||||
<Preference
|
||||
<com.android.settingslib.RestrictedPreference
|
||||
android:fragment="com.android.settings.bluetooth.BluetoothPairingDetail"
|
||||
android:key="add_bt_devices"
|
||||
android:title="@string/connected_device_add_device_title"
|
||||
android:icon="@drawable/ic_menu_add"
|
||||
android:summary="@string/connected_device_add_device_summary"
|
||||
settings:allowDividerAbove="true"/>
|
||||
settings:allowDividerAbove="true"
|
||||
settings:userRestriction="no_config_bluetooth"
|
||||
settings:useAdminDisabledSummary="true"/>
|
||||
|
||||
<Preference
|
||||
android:fragment="com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment"
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:key="data_usage_cellular_screen"
|
||||
android:title="@string/data_usage_summary_title">
|
||||
android:key="data_usage_cellular_screen">
|
||||
|
||||
<com.android.settings.datausage.TemplatePreferenceCategory
|
||||
android:key="mobile_category"
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:key="data_usage_wifi_screen"
|
||||
android:title="@string/data_usage_summary_title">
|
||||
android:key="data_usage_wifi_screen">
|
||||
|
||||
<com.android.settings.datausage.TemplatePreferenceCategory
|
||||
android:key="wifi_category"
|
||||
|
||||
42
res/xml/time_zone_prefs.xml
Normal file
42
res/xml/time_zone_prefs.xml
Normal file
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2018 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.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:key="time_zone_settings_screen"
|
||||
android:title="@string/date_time_set_timezone">
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="time_zone_region_preference_category">
|
||||
<com.android.settingslib.RestrictedPreference
|
||||
android:key="region"
|
||||
android:title="@string/date_time_select_region"
|
||||
android:summary="@string/summary_placeholder" />
|
||||
<com.android.settingslib.RestrictedPreference
|
||||
android:key="region_zone"
|
||||
android:title="@string/date_time_select_zone"
|
||||
android:summary="@string/summary_placeholder" />
|
||||
<com.android.settingslib.widget.FooterPreference/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="time_zone_fixed_offset_preference_category">
|
||||
<com.android.settingslib.RestrictedPreference
|
||||
android:key="fixed_offset"
|
||||
android:title="@string/date_time_select_fixed_offset_time_zones"
|
||||
android:summary="@string/summary_placeholder"/>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:key="user_settings_screen"
|
||||
android:title="@string/user_settings_title">
|
||||
|
||||
@@ -32,25 +31,6 @@
|
||||
android:icon="@drawable/ic_menu_add"
|
||||
android:order="20"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="auto_sync_account_data"
|
||||
android:title="@string/auto_sync_account_title"
|
||||
android:summary="@string/auto_sync_account_summary"
|
||||
android:order="102"
|
||||
settings:allowDividerAbove="true"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="auto_sync_work_account_data"
|
||||
android:title="@string/account_settings_menu_auto_sync_work"
|
||||
android:summary="@string/auto_sync_account_summary"
|
||||
android:order="103"/>
|
||||
|
||||
<SwitchPreference
|
||||
android:key="auto_sync_personal_account_data"
|
||||
android:title="@string/account_settings_menu_auto_sync_personal"
|
||||
android:summary="@string/auto_sync_account_summary"
|
||||
android:order="104"/>
|
||||
|
||||
<com.android.settingslib.RestrictedSwitchPreference
|
||||
android:key="user_settings_add_users_when_locked"
|
||||
android:title="@string/user_add_on_lockscreen_menu"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||
android:key="zen_mode_behavior_settings_page"
|
||||
android:title="@string/zen_mode_behavior_settings_title"
|
||||
settings:initialExpandedChildrenCount="7">
|
||||
settings:initialExpandedChildrenCount="8">
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/zen_mode_behavior_allow_title"
|
||||
@@ -34,8 +34,12 @@
|
||||
<!-- Media -->
|
||||
<SwitchPreference
|
||||
android:key="zen_mode_media"
|
||||
android:title="@string/zen_mode_media_system_other"
|
||||
android:summary="@string/zen_mode_media_system_other_secondary_text"/>
|
||||
android:title="@string/zen_mode_media"/>
|
||||
|
||||
<!-- System -->
|
||||
<SwitchPreference
|
||||
android:key="zen_mode_system"
|
||||
android:title="@string/zen_mode_system"/>
|
||||
|
||||
<!-- Reminders -->
|
||||
<SwitchPreference
|
||||
|
||||
@@ -23,8 +23,6 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -51,28 +49,6 @@ public class VibrationSettings extends DashboardFragment {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
|
||||
return buildControllers(context, getLifecycle());
|
||||
}
|
||||
|
||||
public static List<AbstractPreferenceController> buildControllers(Context context,
|
||||
Lifecycle lifecycle) {
|
||||
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
final NotificationVibrationIntensityPreferenceController notifVibPrefController =
|
||||
new NotificationVibrationIntensityPreferenceController(context);
|
||||
final HapticFeedbackIntensityPreferenceController hapticPreferenceController =
|
||||
new HapticFeedbackIntensityPreferenceController(context);
|
||||
controllers.add(hapticPreferenceController);
|
||||
controllers.add(notifVibPrefController);
|
||||
if (lifecycle != null) {
|
||||
lifecycle.addObserver(hapticPreferenceController);
|
||||
lifecycle.addObserver(notifVibPrefController);
|
||||
}
|
||||
return controllers;
|
||||
}
|
||||
|
||||
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider() {
|
||||
@Override
|
||||
@@ -84,11 +60,5 @@ public class VibrationSettings extends DashboardFragment {
|
||||
indexables.add(indexable);
|
||||
return indexables;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AbstractPreferenceController> createPreferenceControllers(
|
||||
Context context) {
|
||||
return buildControllers(context, null /* lifecycle */);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@ import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.dashboard.SummaryLoader;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.users.AutoSyncDataPreferenceController;
|
||||
import com.android.settings.users.AutoSyncPersonalDataPreferenceController;
|
||||
import com.android.settings.users.AutoSyncWorkDataPreferenceController;
|
||||
import com.android.settingslib.accounts.AuthenticatorHelper;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
|
||||
@@ -69,6 +72,9 @@ public class AccountDashboardFragment extends DashboardFragment {
|
||||
new AccountPreferenceController(context, this, authorities);
|
||||
getLifecycle().addObserver(accountPrefController);
|
||||
controllers.add(accountPrefController);
|
||||
controllers.add(new AutoSyncDataPreferenceController(context, this /*parent */));
|
||||
controllers.add(new AutoSyncPersonalDataPreferenceController(context, this /*parent */));
|
||||
controllers.add(new AutoSyncWorkDataPreferenceController(context, this /* parent */));
|
||||
return controllers;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.Loader;
|
||||
import android.content.UriPermission;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageDataObserver;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -487,7 +486,7 @@ public class AppStorageSettings extends AppInfoWithHeader
|
||||
.create();
|
||||
case DLG_CANNOT_CLEAR_DATA:
|
||||
return new AlertDialog.Builder(getActivity())
|
||||
.setTitle(getActivity().getText(R.string.clear_failed_dlg_title))
|
||||
.setTitle(getActivity().getText(R.string.clear_user_data_text))
|
||||
.setMessage(getActivity().getText(R.string.clear_failed_dlg_text))
|
||||
.setNeutralButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
|
||||
@@ -58,9 +58,17 @@ public class BackupSettingsActivity extends Activity implements Indexable {
|
||||
"No manufacturer settings found, launching the backup settings directly");
|
||||
}
|
||||
Intent intent = backupHelper.getIntentForBackupSettings();
|
||||
// enable the activity before launching it
|
||||
getPackageManager().setComponentEnabledSetting(intent.getComponent(),
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
|
||||
try {
|
||||
// enable the activity before launching it
|
||||
getPackageManager().setComponentEnabledSetting(
|
||||
intent.getComponent(),
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
PackageManager.DONT_KILL_APP);
|
||||
} catch (SecurityException e) {
|
||||
Log.w(TAG, "Trying to enable activity " + intent.getComponent() + " but couldn't: "
|
||||
+ e.getMessage());
|
||||
// the activity may already be enabled
|
||||
}
|
||||
|
||||
// use startActivityForResult to let the activity check the caller signature
|
||||
startActivityForResult(intent, 1);
|
||||
|
||||
@@ -34,8 +34,6 @@ import java.util.List;
|
||||
* Abstract class to consolidate utility between preference controllers and act as an interface
|
||||
* for Slices. The abstract classes that inherit from this class will act as the direct interfaces
|
||||
* for each type when plugging into Slices.
|
||||
*
|
||||
* TODO (b/73074893) Add Lifecycle Setting method.
|
||||
*/
|
||||
public abstract class BasePreferenceController extends AbstractPreferenceController {
|
||||
|
||||
|
||||
@@ -19,11 +19,11 @@ package com.android.settings.datetime;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import android.util.FeatureFlagUtils;
|
||||
|
||||
import com.android.settings.core.FeatureFlags;
|
||||
import com.android.settings.core.PreferenceControllerMixin;
|
||||
import com.android.settings.datetime.timezone.ZonePicker;
|
||||
import com.android.settings.datetime.timezone.TimeZoneSettings;
|
||||
import com.android.settingslib.RestrictedPreference;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.datetime.ZoneGetter;
|
||||
@@ -51,7 +51,7 @@ public class TimeZonePreferenceController extends AbstractPreferenceController
|
||||
return;
|
||||
}
|
||||
if (mZonePickerV2) {
|
||||
preference.setFragment(ZonePicker.class.getName());
|
||||
preference.setFragment(TimeZoneSettings.class.getName());
|
||||
}
|
||||
preference.setSummary(getTimeZoneOffsetAndName());
|
||||
if( !((RestrictedPreference) preference).isDisabledByAdmin()) {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.datetime.timezone;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
public abstract class BaseTimeZonePreferenceController extends BasePreferenceController {
|
||||
private OnPreferenceClickListener mOnClickListener;
|
||||
|
||||
protected BaseTimeZonePreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlePreferenceTreeClick(Preference preference) {
|
||||
if (mOnClickListener == null || !Objects.equal(getPreferenceKey(), preference.getKey())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mOnClickListener.onClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setOnClickListener(OnPreferenceClickListener listener) {
|
||||
mOnClickListener = listener;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.datetime.timezone;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
public class FixedOffsetPreferenceController extends BaseTimeZonePreferenceController {
|
||||
|
||||
private static final String PREFERENCE_KEY = "fixed_offset";
|
||||
|
||||
private TimeZoneInfo mTimeZoneInfo;
|
||||
|
||||
public FixedOffsetPreferenceController(Context context) {
|
||||
super(context, PREFERENCE_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
// This is a Spannable object, which contains TTS span. It shouldn't be converted to String.
|
||||
return mTimeZoneInfo == null ? "" : mTimeZoneInfo.getGmtOffset();
|
||||
}
|
||||
|
||||
public void setTimeZoneInfo(TimeZoneInfo timeZoneInfo) {
|
||||
mTimeZoneInfo = timeZoneInfo;
|
||||
}
|
||||
|
||||
public TimeZoneInfo getTimeZoneInfo() {
|
||||
return mTimeZoneInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.datetime.timezone;
|
||||
|
||||
/**
|
||||
* Callback when a preference is clicked in {@class TimeZoneSettings}
|
||||
*/
|
||||
public interface OnPreferenceClickListener {
|
||||
void onClick();
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.datetime.timezone;
|
||||
|
||||
import android.content.Context;
|
||||
import android.icu.text.LocaleDisplayNames;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class RegionPreferenceController extends BaseTimeZonePreferenceController {
|
||||
private static final String PREFERENCE_KEY = "region";
|
||||
|
||||
private final LocaleDisplayNames mLocaleDisplayNames;
|
||||
private String mRegionId = "";
|
||||
|
||||
public RegionPreferenceController(Context context) {
|
||||
super(context, PREFERENCE_KEY);
|
||||
Locale locale = context.getResources().getConfiguration().getLocales().get(0);
|
||||
mLocaleDisplayNames = LocaleDisplayNames.getInstance(locale);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
return mLocaleDisplayNames.regionDisplayName(mRegionId);
|
||||
}
|
||||
|
||||
public void setRegionId(String regionId) {
|
||||
mRegionId = regionId;
|
||||
}
|
||||
|
||||
public String getRegionId() {
|
||||
return mRegionId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.datetime.timezone;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
public class RegionZonePreferenceController extends BaseTimeZonePreferenceController {
|
||||
private static final String PREFERENCE_KEY = "region_zone";
|
||||
|
||||
private TimeZoneInfo mTimeZoneInfo;
|
||||
private boolean mIsClickable;
|
||||
|
||||
public RegionZonePreferenceController(Context context) {
|
||||
super(context, PREFERENCE_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
preference.setEnabled(isClickable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
return mTimeZoneInfo == null ? ""
|
||||
: SpannableUtil.getResourcesText(mContext.getResources(),
|
||||
R.string.zone_info_exemplar_location_and_offset,
|
||||
mTimeZoneInfo.getExemplarLocation(), mTimeZoneInfo.getGmtOffset());
|
||||
}
|
||||
|
||||
public void setTimeZoneInfo(TimeZoneInfo timeZoneInfo) {
|
||||
mTimeZoneInfo = timeZoneInfo;
|
||||
}
|
||||
|
||||
public TimeZoneInfo getTimeZoneInfo() {
|
||||
return mTimeZoneInfo;
|
||||
}
|
||||
|
||||
public void setClickable(boolean clickable) {
|
||||
mIsClickable = clickable;
|
||||
}
|
||||
|
||||
public boolean isClickable() {
|
||||
return mIsClickable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.datetime.timezone;
|
||||
|
||||
import android.content.Context;
|
||||
import android.icu.impl.OlsonTimeZone;
|
||||
import android.icu.text.DateFormat;
|
||||
import android.icu.text.DisplayContext;
|
||||
import android.icu.text.SimpleDateFormat;
|
||||
import android.icu.util.Calendar;
|
||||
import android.icu.util.TimeZone;
|
||||
import android.icu.util.TimeZoneTransition;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.widget.FooterPreference;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class TimeZoneInfoPreferenceController extends BaseTimeZonePreferenceController {
|
||||
private static final String PREFERENCE_KEY = FooterPreference.KEY_FOOTER;
|
||||
|
||||
private TimeZoneInfo mTimeZoneInfo;
|
||||
private final DateFormat mDateFormat;
|
||||
private final Date mDate;
|
||||
|
||||
public TimeZoneInfoPreferenceController(Context context) {
|
||||
this(context, new Date());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
TimeZoneInfoPreferenceController(Context context, Date date) {
|
||||
super(context, PREFERENCE_KEY);
|
||||
mDateFormat = DateFormat.getDateInstance(SimpleDateFormat.LONG);
|
||||
mDateFormat.setContext(DisplayContext.CAPITALIZATION_NONE);
|
||||
mDate = date;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
CharSequence formattedTimeZone = mTimeZoneInfo == null ? "" : formatInfo(mTimeZoneInfo);
|
||||
preference.setTitle(formattedTimeZone);
|
||||
preference.setVisible(mTimeZoneInfo != null);
|
||||
}
|
||||
|
||||
public void setTimeZoneInfo(TimeZoneInfo timeZoneInfo) {
|
||||
mTimeZoneInfo = timeZoneInfo;
|
||||
}
|
||||
|
||||
public TimeZoneInfo getTimeZoneInfo() {
|
||||
return mTimeZoneInfo;
|
||||
}
|
||||
|
||||
private CharSequence formatOffsetAndName(TimeZoneInfo item) {
|
||||
String name = item.getGenericName();
|
||||
if (name == null) {
|
||||
if (item.getTimeZone().inDaylightTime(mDate)) {
|
||||
name = item.getDaylightName();
|
||||
} else {
|
||||
name = item.getStandardName();
|
||||
}
|
||||
}
|
||||
if (name == null) {
|
||||
return item.getGmtOffset().toString();
|
||||
} else {
|
||||
return SpannableUtil.getResourcesText(mContext.getResources(),
|
||||
R.string.zone_info_offset_and_name, item.getGmtOffset(),
|
||||
name);
|
||||
}
|
||||
}
|
||||
|
||||
private CharSequence formatInfo(TimeZoneInfo item) {
|
||||
final CharSequence offsetAndName = formatOffsetAndName(item);
|
||||
final TimeZone timeZone = item.getTimeZone();
|
||||
if (!timeZone.observesDaylightTime()) {
|
||||
return mContext.getString(R.string.zone_info_footer_no_dst, offsetAndName);
|
||||
}
|
||||
|
||||
final TimeZoneTransition nextDstTransition = findNextDstTransition(timeZone);
|
||||
if (nextDstTransition == null) {
|
||||
return null;
|
||||
}
|
||||
final boolean toDst = nextDstTransition.getTo().getDSTSavings() != 0;
|
||||
String timeType = toDst ? item.getDaylightName() : item.getStandardName();
|
||||
if (timeType == null) {
|
||||
// Fall back to generic "summer time" and "standard time" if the time zone has no
|
||||
// specific names.
|
||||
timeType = toDst ?
|
||||
mContext.getString(R.string.zone_time_type_dst) :
|
||||
mContext.getString(R.string.zone_time_type_standard);
|
||||
|
||||
}
|
||||
final Calendar transitionTime = Calendar.getInstance(timeZone);
|
||||
transitionTime.setTimeInMillis(nextDstTransition.getTime());
|
||||
final String date = mDateFormat.format(transitionTime);
|
||||
return SpannableUtil.getResourcesText(mContext.getResources(),
|
||||
R.string.zone_info_footer, offsetAndName, timeType, date);
|
||||
}
|
||||
|
||||
private TimeZoneTransition findNextDstTransition(TimeZone timeZone) {
|
||||
if (!(timeZone instanceof OlsonTimeZone)) {
|
||||
return null;
|
||||
}
|
||||
final OlsonTimeZone olsonTimeZone = (OlsonTimeZone) timeZone;
|
||||
TimeZoneTransition transition = olsonTimeZone.getNextTransition(
|
||||
mDate.getTime(), /* inclusive */ false);
|
||||
do {
|
||||
if (transition.getTo().getDSTSavings() != transition.getFrom().getDSTSavings()) {
|
||||
break;
|
||||
}
|
||||
transition = olsonTimeZone.getNextTransition(
|
||||
transition.getTime(), /*inclusive */ false);
|
||||
} while (transition != null);
|
||||
return transition;
|
||||
}
|
||||
|
||||
}
|
||||
372
src/com/android/settings/datetime/timezone/TimeZoneSettings.java
Normal file
372
src/com/android/settings/datetime/timezone/TimeZoneSettings.java
Normal file
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.datetime.timezone;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlarmManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.icu.util.TimeZone;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.v7.preference.PreferenceCategory;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.datetime.timezone.model.FilteredCountryTimeZones;
|
||||
import com.android.settings.datetime.timezone.model.TimeZoneData;
|
||||
import com.android.settings.datetime.timezone.model.TimeZoneDataLoader;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The class displays a time zone picker either by regions or fixed offset time zones.
|
||||
*/
|
||||
public class TimeZoneSettings extends DashboardFragment {
|
||||
|
||||
private static final String TAG = "TimeZoneSettings";
|
||||
|
||||
private static final int MENU_BY_REGION = Menu.FIRST;
|
||||
private static final int MENU_BY_OFFSET = Menu.FIRST + 1;
|
||||
|
||||
private static final int REQUEST_CODE_REGION_PICKER = 1;
|
||||
private static final int REQUEST_CODE_ZONE_PICKER = 2;
|
||||
private static final int REQUEST_CODE_FIXED_OFFSET_ZONE_PICKER = 3;
|
||||
|
||||
private static final String PREF_KEY_REGION = "time_zone_region";
|
||||
private static final String PREF_KEY_REGION_CATEGORY = "time_zone_region_preference_category";
|
||||
private static final String PREF_KEY_FIXED_OFFSET_CATEGORY =
|
||||
"time_zone_fixed_offset_preference_category";
|
||||
|
||||
private Locale mLocale;
|
||||
private boolean mSelectByRegion;
|
||||
private TimeZoneData mTimeZoneData;
|
||||
|
||||
private String mSelectedTimeZoneId;
|
||||
private TimeZoneInfo.Formatter mTimeZoneInfoFormatter;
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return MetricsProto.MetricsEvent.ZONE_PICKER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.time_zone_prefs;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called during onAttach
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@Override
|
||||
public List<AbstractPreferenceController> createPreferenceControllers(Context context) {
|
||||
mLocale = context.getResources().getConfiguration().getLocales().get(0);
|
||||
mTimeZoneInfoFormatter = new TimeZoneInfo.Formatter(mLocale, new Date());
|
||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
RegionPreferenceController regionPreferenceController =
|
||||
new RegionPreferenceController(context);
|
||||
regionPreferenceController.setOnClickListener(this::onRegionPreferenceClicked);
|
||||
RegionZonePreferenceController regionZonePreferenceController =
|
||||
new RegionZonePreferenceController(context);
|
||||
regionZonePreferenceController.setOnClickListener(this::onRegionZonePreferenceClicked);
|
||||
TimeZoneInfoPreferenceController timeZoneInfoPreferenceController =
|
||||
new TimeZoneInfoPreferenceController(context);
|
||||
FixedOffsetPreferenceController fixedOffsetPreferenceController =
|
||||
new FixedOffsetPreferenceController(context);
|
||||
fixedOffsetPreferenceController.setOnClickListener(this::onFixedOffsetPreferenceClicked);
|
||||
|
||||
controllers.add(regionPreferenceController);
|
||||
controllers.add(regionZonePreferenceController);
|
||||
controllers.add(timeZoneInfoPreferenceController);
|
||||
controllers.add(fixedOffsetPreferenceController);
|
||||
return controllers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
// Hide all interactive preferences
|
||||
setPreferenceCategoryVisible((PreferenceCategory) findPreference(
|
||||
PREF_KEY_REGION_CATEGORY), false);
|
||||
setPreferenceCategoryVisible((PreferenceCategory) findPreference(
|
||||
PREF_KEY_FIXED_OFFSET_CATEGORY), false);
|
||||
|
||||
// Start loading TimeZoneData
|
||||
getLoaderManager().initLoader(0, null, new TimeZoneDataLoader.LoaderCreator(
|
||||
getContext(), this::onTimeZoneDataReady));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (resultCode != Activity.RESULT_OK || data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (requestCode) {
|
||||
case REQUEST_CODE_REGION_PICKER:
|
||||
case REQUEST_CODE_ZONE_PICKER: {
|
||||
String regionId = data.getStringExtra(RegionSearchPicker.EXTRA_RESULT_REGION_ID);
|
||||
String tzId = data.getStringExtra(RegionZonePicker.EXTRA_RESULT_TIME_ZONE_ID);
|
||||
// Ignore the result if user didn't change the region or time zone.
|
||||
if (!Objects.equals(regionId, use(RegionPreferenceController.class).getRegionId())
|
||||
|| !Objects.equals(tzId, mSelectedTimeZoneId)) {
|
||||
onRegionZoneChanged(regionId, tzId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case REQUEST_CODE_FIXED_OFFSET_ZONE_PICKER: {
|
||||
String tzId = data.getStringExtra(FixedOffsetPicker.EXTRA_RESULT_TIME_ZONE_ID);
|
||||
// Ignore the result if user didn't change the time zone.
|
||||
if (tzId != null && !tzId.equals(mSelectedTimeZoneId)) {
|
||||
onFixedOffsetZoneChanged(tzId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setTimeZoneData(TimeZoneData timeZoneData) {
|
||||
mTimeZoneData = timeZoneData;
|
||||
}
|
||||
|
||||
private void onTimeZoneDataReady(TimeZoneData timeZoneData) {
|
||||
if (mTimeZoneData == null && timeZoneData != null) {
|
||||
mTimeZoneData = timeZoneData;
|
||||
setupForCurrentTimeZone();
|
||||
getActivity().invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void onRegionPreferenceClicked() {
|
||||
startPickerFragment(RegionSearchPicker.class, new Bundle(), REQUEST_CODE_REGION_PICKER);
|
||||
}
|
||||
|
||||
private void onRegionZonePreferenceClicked() {
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(RegionZonePicker.EXTRA_REGION_ID,
|
||||
use(RegionPreferenceController.class).getRegionId());
|
||||
startPickerFragment(RegionZonePicker.class, args, REQUEST_CODE_ZONE_PICKER);
|
||||
}
|
||||
|
||||
private void onFixedOffsetPreferenceClicked() {
|
||||
startPickerFragment(FixedOffsetPicker.class, new Bundle(),
|
||||
REQUEST_CODE_FIXED_OFFSET_ZONE_PICKER);
|
||||
}
|
||||
|
||||
private void startPickerFragment(Class<? extends BaseTimeZonePicker> fragmentClass, Bundle args,
|
||||
int resultRequestCode) {
|
||||
new SubSettingLauncher(getContext())
|
||||
.setDestination(fragmentClass.getCanonicalName())
|
||||
.setArguments(args)
|
||||
.setSourceMetricsCategory(getMetricsCategory())
|
||||
.setResultListener(this, resultRequestCode)
|
||||
.launch();
|
||||
}
|
||||
|
||||
private void setDisplayedRegion(String regionId) {
|
||||
use(RegionPreferenceController.class).setRegionId(regionId);
|
||||
updatePreferenceStates();
|
||||
}
|
||||
|
||||
private void setDisplayedTimeZoneInfo(String regionId, String tzId) {
|
||||
final TimeZoneInfo tzInfo = tzId == null ? null : mTimeZoneInfoFormatter.format(tzId);
|
||||
final FilteredCountryTimeZones countryTimeZones =
|
||||
mTimeZoneData.lookupCountryTimeZones(regionId);
|
||||
|
||||
use(RegionZonePreferenceController.class).setTimeZoneInfo(tzInfo);
|
||||
// Only clickable when the region has more than 1 time zones or no time zone is selected.
|
||||
|
||||
use(RegionZonePreferenceController.class).setClickable(tzInfo == null ||
|
||||
(countryTimeZones != null && countryTimeZones.getTimeZoneIds().size() > 1));
|
||||
use(TimeZoneInfoPreferenceController.class).setTimeZoneInfo(tzInfo);
|
||||
|
||||
updatePreferenceStates();
|
||||
}
|
||||
|
||||
private void setDisplayedFixedOffsetTimeZoneInfo(String tzId) {
|
||||
if (isFixedOffset(tzId)) {
|
||||
use(FixedOffsetPreferenceController.class).setTimeZoneInfo(
|
||||
mTimeZoneInfoFormatter.format(tzId));
|
||||
} else {
|
||||
use(FixedOffsetPreferenceController.class).setTimeZoneInfo(null);
|
||||
}
|
||||
updatePreferenceStates();
|
||||
}
|
||||
|
||||
private void onRegionZoneChanged(String regionId, String tzId) {
|
||||
FilteredCountryTimeZones countryTimeZones =
|
||||
mTimeZoneData.lookupCountryTimeZones(regionId);
|
||||
if (countryTimeZones == null || !countryTimeZones.getTimeZoneIds().contains(tzId)) {
|
||||
Log.e(TAG, "Unknown time zone id is selected: " + tzId);
|
||||
return;
|
||||
}
|
||||
|
||||
mSelectedTimeZoneId = tzId;
|
||||
setDisplayedRegion(regionId);
|
||||
setDisplayedTimeZoneInfo(regionId, mSelectedTimeZoneId);
|
||||
saveTimeZone(regionId, mSelectedTimeZoneId);
|
||||
}
|
||||
|
||||
private void onFixedOffsetZoneChanged(String tzId) {
|
||||
mSelectedTimeZoneId = tzId;
|
||||
setDisplayedFixedOffsetTimeZoneInfo(tzId);
|
||||
saveTimeZone(null, mSelectedTimeZoneId);
|
||||
}
|
||||
|
||||
private void saveTimeZone(String regionId, String tzId) {
|
||||
SharedPreferences.Editor editor = getPreferenceManager().getSharedPreferences().edit();
|
||||
if (regionId == null) {
|
||||
editor.remove(PREF_KEY_REGION);
|
||||
} else {
|
||||
editor.putString(PREF_KEY_REGION, regionId);
|
||||
}
|
||||
editor.apply();
|
||||
getActivity().getSystemService(AlarmManager.class).setTimeZone(tzId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
menu.add(0, MENU_BY_REGION, 0, R.string.zone_menu_by_region);
|
||||
menu.add(0, MENU_BY_OFFSET, 0, R.string.zone_menu_by_offset);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
// Do not show menu when data is not ready,
|
||||
menu.findItem(MENU_BY_REGION).setVisible(mTimeZoneData != null && !mSelectByRegion);
|
||||
menu.findItem(MENU_BY_OFFSET).setVisible(mTimeZoneData != null && mSelectByRegion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_BY_REGION:
|
||||
setSelectByRegion(true);
|
||||
return true;
|
||||
|
||||
case MENU_BY_OFFSET:
|
||||
setSelectByRegion(false);
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setupForCurrentTimeZone() {
|
||||
mSelectedTimeZoneId = TimeZone.getDefault().getID();
|
||||
setSelectByRegion(!isFixedOffset(mSelectedTimeZoneId));
|
||||
}
|
||||
|
||||
private static boolean isFixedOffset(String tzId) {
|
||||
return tzId.startsWith("Etc/GMT") || tzId.equals("Etc/UTC");
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch the current view to select region or select fixed offset time zone.
|
||||
* When showing the selected region, it guess the selected region from time zone id.
|
||||
* See {@link #findRegionIdForTzId} for more info.
|
||||
*/
|
||||
private void setSelectByRegion(boolean selectByRegion) {
|
||||
mSelectByRegion = selectByRegion;
|
||||
setPreferenceCategoryVisible((PreferenceCategory) findPreference(
|
||||
PREF_KEY_REGION_CATEGORY), selectByRegion);
|
||||
setPreferenceCategoryVisible((PreferenceCategory) findPreference(
|
||||
PREF_KEY_FIXED_OFFSET_CATEGORY), !selectByRegion);
|
||||
final String localeRegionId = getLocaleRegionId();
|
||||
final Set<String> allCountryIsoCodes = mTimeZoneData.getRegionIds();
|
||||
|
||||
String displayRegion = allCountryIsoCodes.contains(localeRegionId) ? localeRegionId : null;
|
||||
setDisplayedRegion(displayRegion);
|
||||
setDisplayedTimeZoneInfo(displayRegion, null);
|
||||
|
||||
if (!mSelectByRegion) {
|
||||
setDisplayedFixedOffsetTimeZoneInfo(mSelectedTimeZoneId);
|
||||
return;
|
||||
}
|
||||
|
||||
String regionId = findRegionIdForTzId(mSelectedTimeZoneId);
|
||||
if (regionId != null) {
|
||||
setDisplayedRegion(regionId);
|
||||
setDisplayedTimeZoneInfo(regionId, mSelectedTimeZoneId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the a region associated with the specified time zone, based on the time zone data.
|
||||
* If there are multiple regions associated with the given time zone, the priority will be given
|
||||
* to the region the user last picked and the country in user's locale.
|
||||
* @return null if no region associated with the time zone
|
||||
*/
|
||||
private String findRegionIdForTzId(String tzId) {
|
||||
return findRegionIdForTzId(tzId,
|
||||
getPreferenceManager().getSharedPreferences().getString(PREF_KEY_REGION, null),
|
||||
getLocaleRegionId());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String findRegionIdForTzId(String tzId, String sharePrefRegionId, String localeRegionId) {
|
||||
final Set<String> matchedRegions = mTimeZoneData.lookupCountryCodesForZoneId(tzId);
|
||||
if (matchedRegions.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
if (sharePrefRegionId != null && matchedRegions.contains(sharePrefRegionId)) {
|
||||
return sharePrefRegionId;
|
||||
}
|
||||
if (localeRegionId != null && matchedRegions.contains(localeRegionId)) {
|
||||
return localeRegionId;
|
||||
}
|
||||
|
||||
return matchedRegions.toArray(new String[matchedRegions.size()])[0];
|
||||
}
|
||||
|
||||
private void setPreferenceCategoryVisible(PreferenceCategory category,
|
||||
boolean isVisible) {
|
||||
// Hiding category doesn't hide all the children preference. Set visibility of its children.
|
||||
// Do not care grandchildren as time_zone_pref.xml has only 2 levels.
|
||||
category.setVisible(isVisible);
|
||||
for (int i = 0; i < category.getPreferenceCount(); i++) {
|
||||
category.getPreference(i).setVisible(isVisible);
|
||||
}
|
||||
}
|
||||
|
||||
private String getLocaleRegionId() {
|
||||
return mLocale.getCountry().toUpperCase(Locale.US);
|
||||
}
|
||||
}
|
||||
@@ -35,18 +35,15 @@ import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.R;
|
||||
import com.android.settingslib.utils.PowerUtil;
|
||||
import com.android.settingslib.utils.StringUtil;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BatteryInfo {
|
||||
private static final long SEVEN_MINUTES_MICROS = TimeUnit.MINUTES.toMicros(7);
|
||||
private static final long FIFTEEN_MINUTES_MICROS = TimeUnit.MINUTES.toMicros(15);
|
||||
private static final long ONE_DAY_MICROS = TimeUnit.DAYS.toMicros(1);
|
||||
|
||||
public CharSequence chargeLabel;
|
||||
public CharSequence remainingLabel;
|
||||
public int batteryLevel;
|
||||
public boolean discharging = true;
|
||||
public long remainingTimeUs = 0;
|
||||
public long averageTimeToDischarge = Estimate.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN;
|
||||
public String batteryPercentString;
|
||||
public String statusLabel;
|
||||
private boolean mCharging;
|
||||
@@ -180,16 +177,18 @@ public class BatteryInfo {
|
||||
BatteryUtils
|
||||
.logRuntime(LOG_TAG, "time for enhanced BatteryInfo", startTime);
|
||||
return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats,
|
||||
elapsedRealtimeUs, shortString,
|
||||
PowerUtil.convertMsToUs(estimate.estimateMillis),
|
||||
estimate.isBasedOnUsage);
|
||||
estimate, elapsedRealtimeUs, shortString);
|
||||
}
|
||||
}
|
||||
long prediction = discharging
|
||||
? stats.computeBatteryTimeRemaining(elapsedRealtimeUs) : 0;
|
||||
Estimate estimate = new Estimate(
|
||||
PowerUtil.convertUsToMs(prediction),
|
||||
false, /* isBasedOnUsage */
|
||||
Estimate.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
|
||||
BatteryUtils.logRuntime(LOG_TAG, "time for regular BatteryInfo", startTime);
|
||||
return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats,
|
||||
elapsedRealtimeUs, shortString, prediction, false);
|
||||
estimate, elapsedRealtimeUs, shortString);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -204,25 +203,29 @@ public class BatteryInfo {
|
||||
@WorkerThread
|
||||
public static BatteryInfo getBatteryInfoOld(Context context, Intent batteryBroadcast,
|
||||
BatteryStats stats, long elapsedRealtimeUs, boolean shortString) {
|
||||
return getBatteryInfo(context, batteryBroadcast, stats, elapsedRealtimeUs, shortString,
|
||||
stats.computeBatteryTimeRemaining(elapsedRealtimeUs), false);
|
||||
Estimate estimate = new Estimate(
|
||||
PowerUtil.convertUsToMs(stats.computeBatteryTimeRemaining(elapsedRealtimeUs)),
|
||||
false,
|
||||
Estimate.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
|
||||
return getBatteryInfo(context, batteryBroadcast, stats, estimate, elapsedRealtimeUs,
|
||||
shortString);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
|
||||
BatteryStats stats, long elapsedRealtimeUs, boolean shortString, long drainTimeUs,
|
||||
boolean basedOnUsage) {
|
||||
BatteryStats stats, Estimate estimate, long elapsedRealtimeUs, boolean shortString) {
|
||||
final long startTime = System.currentTimeMillis();
|
||||
BatteryInfo info = new BatteryInfo();
|
||||
info.mStats = stats;
|
||||
info.batteryLevel = Utils.getBatteryLevel(batteryBroadcast);
|
||||
info.batteryPercentString = Utils.formatPercentage(info.batteryLevel);
|
||||
info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
|
||||
info.averageTimeToDischarge = estimate.averageDischargeTime;
|
||||
final Resources resources = context.getResources();
|
||||
|
||||
info.statusLabel = Utils.getBatteryStatus(resources, batteryBroadcast);
|
||||
if (!info.mCharging) {
|
||||
updateBatteryInfoDischarging(context, shortString, drainTimeUs, basedOnUsage, info);
|
||||
updateBatteryInfoDischarging(context, shortString, estimate, info);
|
||||
} else {
|
||||
updateBatteryInfoCharging(context, batteryBroadcast, stats, elapsedRealtimeUs, info);
|
||||
}
|
||||
@@ -256,20 +259,21 @@ public class BatteryInfo {
|
||||
}
|
||||
|
||||
private static void updateBatteryInfoDischarging(Context context, boolean shortString,
|
||||
long drainTimeUs, boolean basedOnUsage, BatteryInfo info) {
|
||||
Estimate estimate, BatteryInfo info) {
|
||||
final long drainTimeUs = PowerUtil.convertMsToUs(estimate.estimateMillis);
|
||||
if (drainTimeUs > 0) {
|
||||
info.remainingTimeUs = drainTimeUs;
|
||||
info.remainingLabel = PowerUtil.getBatteryRemainingStringFormatted(
|
||||
context,
|
||||
PowerUtil.convertUsToMs(drainTimeUs),
|
||||
null /* percentageString */,
|
||||
basedOnUsage && !shortString
|
||||
estimate.isBasedOnUsage && !shortString
|
||||
);
|
||||
info.chargeLabel = PowerUtil.getBatteryRemainingStringFormatted(
|
||||
context,
|
||||
PowerUtil.convertUsToMs(drainTimeUs),
|
||||
info.batteryPercentString,
|
||||
basedOnUsage && !shortString
|
||||
estimate.isBasedOnUsage && !shortString
|
||||
);
|
||||
} else {
|
||||
info.remainingLabel = null;
|
||||
|
||||
@@ -438,14 +438,15 @@ public class BatteryUtils {
|
||||
|
||||
if (estimate != null) {
|
||||
batteryInfo = BatteryInfo.getBatteryInfo(mContext, batteryBroadcast, stats,
|
||||
elapsedRealtimeUs, false /* shortString */,
|
||||
PowerUtil.convertMsToUs(estimate.estimateMillis),
|
||||
estimate.isBasedOnUsage);
|
||||
estimate, elapsedRealtimeUs, false /* shortString */);
|
||||
} else {
|
||||
estimate = new Estimate(
|
||||
PowerUtil.convertUsToMs(stats.computeBatteryTimeRemaining(elapsedRealtimeUs)),
|
||||
false,
|
||||
Estimate.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN
|
||||
);
|
||||
batteryInfo = BatteryInfo.getBatteryInfo(mContext, batteryBroadcast, stats,
|
||||
elapsedRealtimeUs, false /* shortString */,
|
||||
discharging ? stats.computeBatteryTimeRemaining(elapsedRealtimeUs) : 0,
|
||||
false /* basedOnUsage */);
|
||||
estimate, elapsedRealtimeUs, false /* shortString */);
|
||||
}
|
||||
BatteryUtils.logRuntime(tag, "BatteryInfoLoader.loadInBackground", startTime);
|
||||
|
||||
|
||||
@@ -58,12 +58,10 @@ public class DebugEstimatesLoader extends AsyncLoader<List<BatteryInfo>> {
|
||||
|
||||
Estimate estimate = powerUsageFeatureProvider.getEnhancedBatteryPrediction(context);
|
||||
if (estimate == null) {
|
||||
estimate = new Estimate(0, false);
|
||||
estimate = new Estimate(0, false, Estimate.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
|
||||
}
|
||||
BatteryInfo newInfo = BatteryInfo.getBatteryInfo(getContext(), batteryBroadcast, stats,
|
||||
elapsedRealtimeUs, false,
|
||||
PowerUtil.convertMsToUs(estimate.estimateMillis),
|
||||
estimate.isBasedOnUsage);
|
||||
estimate, elapsedRealtimeUs, false);
|
||||
|
||||
List<BatteryInfo> infos = new ArrayList<>();
|
||||
infos.add(oldinfo);
|
||||
|
||||
@@ -2,11 +2,17 @@ package com.android.settings.fuelgauge;
|
||||
|
||||
public class Estimate {
|
||||
|
||||
public final long estimateMillis;
|
||||
public final boolean isBasedOnUsage;
|
||||
// Value to indicate averageTimeToDischarge could not be obtained
|
||||
public static final int AVERAGE_TIME_TO_DISCHARGE_UNKNOWN = -1;
|
||||
|
||||
public Estimate(long estimateMillis, boolean isBasedOnUsage) {
|
||||
this.estimateMillis = estimateMillis;
|
||||
this.isBasedOnUsage = isBasedOnUsage;
|
||||
}
|
||||
public final long estimateMillis;
|
||||
public final boolean isBasedOnUsage;
|
||||
public final long averageDischargeTime;
|
||||
|
||||
public Estimate(long estimateMillis, boolean isBasedOnUsage,
|
||||
long averageDischargeTime) {
|
||||
this.estimateMillis = estimateMillis;
|
||||
this.isBasedOnUsage = isBasedOnUsage;
|
||||
this.averageDischargeTime = averageDischargeTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ public class RestrictAppPreferenceController extends BasePreferenceController {
|
||||
final AppOpsManager.PackageOps packageOps = packageOpsList.get(i);
|
||||
mAppInfos.add(new AppInfo.Builder()
|
||||
.setPackageName(packageOps.getPackageName())
|
||||
.setUid(packageOps.getUid())
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@@ -130,19 +130,15 @@ public class RestrictedAppDetails extends DashboardFragment {
|
||||
appInfo.packageName, 0 /* flags */);
|
||||
checkBoxPreference.setChecked(true);
|
||||
checkBoxPreference.setTitle(mPackageManager.getApplicationLabel(applicationInfo));
|
||||
checkBoxPreference.setKey(appInfo.packageName);
|
||||
checkBoxPreference.setIcon(
|
||||
Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager,
|
||||
appInfo.packageName,
|
||||
UserHandle.getUserId(
|
||||
mBatteryUtils.getPackageUid(appInfo.packageName))));
|
||||
UserHandle.getUserId(appInfo.uid)));
|
||||
checkBoxPreference.setOnPreferenceChangeListener((pref, value) -> {
|
||||
// change the toggle
|
||||
final int mode = (Boolean) value ? AppOpsManager.MODE_IGNORED
|
||||
: AppOpsManager.MODE_ALLOWED;
|
||||
final String packageName = pref.getKey();
|
||||
final int uid = mBatteryUtils.getPackageUid(packageName);
|
||||
mBatteryUtils.setForceAppStandby(uid, packageName, mode);
|
||||
mBatteryUtils.setForceAppStandby(appInfo.uid, appInfo.packageName, mode);
|
||||
return true;
|
||||
});
|
||||
mRestrictedAppListGroup.addPreference(checkBoxPreference);
|
||||
|
||||
@@ -41,6 +41,7 @@ import android.util.Log;
|
||||
import com.android.internal.os.BatteryStatsHelper;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.fuelgauge.BatteryUtils;
|
||||
import com.android.settingslib.fuelgauge.PowerWhitelistBackend;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.List;
|
||||
@@ -81,11 +82,12 @@ public class AnomalyDetectionJobService extends JobService {
|
||||
final BatteryStatsHelper batteryStatsHelper = new BatteryStatsHelper(this,
|
||||
true /* collectBatteryBroadcast */);
|
||||
final UserManager userManager = getSystemService(UserManager.class);
|
||||
final PowerWhitelistBackend powerWhitelistBackend = PowerWhitelistBackend.getInstance();
|
||||
|
||||
for (JobWorkItem item = params.dequeueWork(); item != null;
|
||||
item = params.dequeueWork()) {
|
||||
saveAnomalyToDatabase(batteryStatsHelper, userManager, batteryDatabaseManager,
|
||||
batteryUtils, policy, contentResolver,
|
||||
batteryUtils, policy, powerWhitelistBackend, contentResolver,
|
||||
item.getIntent().getExtras());
|
||||
}
|
||||
jobFinished(params, false /* wantsReschedule */);
|
||||
@@ -102,7 +104,8 @@ public class AnomalyDetectionJobService extends JobService {
|
||||
@VisibleForTesting
|
||||
void saveAnomalyToDatabase(BatteryStatsHelper batteryStatsHelper, UserManager userManager,
|
||||
BatteryDatabaseManager databaseManager, BatteryUtils batteryUtils,
|
||||
BatteryTipPolicy policy, ContentResolver contentResolver, Bundle bundle) {
|
||||
BatteryTipPolicy policy, PowerWhitelistBackend powerWhitelistBackend,
|
||||
ContentResolver contentResolver, Bundle bundle) {
|
||||
// The Example of intentDimsValue is: 35:{1:{1:{1:10013|}|}|}
|
||||
final StatsDimensionsValue intentDimsValue =
|
||||
bundle.getParcelable(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE);
|
||||
@@ -119,24 +122,25 @@ public class AnomalyDetectionJobService extends JobService {
|
||||
final boolean smartBatteryOn = Settings.Global.getInt(contentResolver,
|
||||
Settings.Global.APP_STANDBY_ENABLED, ON) == ON;
|
||||
final String packageName = batteryUtils.getPackageName(uid);
|
||||
|
||||
if (anomalyType == StatsManagerConfig.AnomalyType.EXCESSIVE_BG) {
|
||||
// TODO(b/72385333): check battery percentage draining in batterystats
|
||||
if (batteryUtils.isLegacyApp(packageName) && batteryUtils.isAppHeavilyUsed(
|
||||
batteryStatsHelper, userManager, uid,
|
||||
policy.excessiveBgDrainPercentage)) {
|
||||
Log.e(TAG, "Excessive detected uid=" + uid);
|
||||
batteryUtils.setForceAppStandby(uid, packageName,
|
||||
AppOpsManager.MODE_IGNORED);
|
||||
databaseManager.insertAnomaly(packageName, anomalyType,
|
||||
smartBatteryOn
|
||||
? AnomalyDatabaseHelper.State.AUTO_HANDLED
|
||||
: AnomalyDatabaseHelper.State.NEW,
|
||||
timeMs);
|
||||
if (!powerWhitelistBackend.isSysWhitelisted(packageName)) {
|
||||
if (anomalyType == StatsManagerConfig.AnomalyType.EXCESSIVE_BG) {
|
||||
// TODO(b/72385333): check battery percentage draining in batterystats
|
||||
if (batteryUtils.isLegacyApp(packageName) && batteryUtils.isAppHeavilyUsed(
|
||||
batteryStatsHelper, userManager, uid,
|
||||
policy.excessiveBgDrainPercentage)) {
|
||||
Log.e(TAG, "Excessive detected uid=" + uid);
|
||||
batteryUtils.setForceAppStandby(uid, packageName,
|
||||
AppOpsManager.MODE_IGNORED);
|
||||
databaseManager.insertAnomaly(uid, packageName, anomalyType,
|
||||
smartBatteryOn
|
||||
? AnomalyDatabaseHelper.State.AUTO_HANDLED
|
||||
: AnomalyDatabaseHelper.State.NEW,
|
||||
timeMs);
|
||||
}
|
||||
} else {
|
||||
databaseManager.insertAnomaly(uid, packageName, anomalyType,
|
||||
AnomalyDatabaseHelper.State.NEW, timeMs);
|
||||
}
|
||||
} else {
|
||||
databaseManager.insertAnomaly(packageName, anomalyType,
|
||||
AnomalyDatabaseHelper.State.NEW, timeMs);
|
||||
}
|
||||
} catch (NullPointerException | IndexOutOfBoundsException e) {
|
||||
Log.e(TAG, "Parse stats dimensions value error.", e);
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.settings.fuelgauge.batterytip;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.settings.fuelgauge.anomaly.Anomaly;
|
||||
|
||||
@@ -33,11 +34,13 @@ public class AppInfo implements Comparable<AppInfo>, Parcelable {
|
||||
*/
|
||||
public final int anomalyType;
|
||||
public final long screenOnTimeMs;
|
||||
public final int uid;
|
||||
|
||||
private AppInfo(AppInfo.Builder builder) {
|
||||
packageName = builder.mPackageName;
|
||||
anomalyType = builder.mAnomalyType;
|
||||
screenOnTimeMs = builder.mScreenOnTimeMs;
|
||||
uid = builder.mUid;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -45,6 +48,7 @@ public class AppInfo implements Comparable<AppInfo>, Parcelable {
|
||||
packageName = in.readString();
|
||||
anomalyType = in.readInt();
|
||||
screenOnTimeMs = in.readLong();
|
||||
uid = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,6 +66,29 @@ public class AppInfo implements Comparable<AppInfo>, Parcelable {
|
||||
dest.writeString(packageName);
|
||||
dest.writeInt(anomalyType);
|
||||
dest.writeLong(screenOnTimeMs);
|
||||
dest.writeInt(uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "packageName=" + packageName + ",anomalyType=" + anomalyType + ",screenTime="
|
||||
+ screenOnTimeMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof AppInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AppInfo other = (AppInfo) obj;
|
||||
return anomalyType == other.anomalyType
|
||||
&& uid == other.uid
|
||||
&& screenOnTimeMs == other.screenOnTimeMs
|
||||
&& TextUtils.equals(packageName, other.packageName);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
|
||||
@@ -78,6 +105,7 @@ public class AppInfo implements Comparable<AppInfo>, Parcelable {
|
||||
private int mAnomalyType;
|
||||
private String mPackageName;
|
||||
private long mScreenOnTimeMs;
|
||||
private int mUid;
|
||||
|
||||
public Builder setAnomalyType(int type) {
|
||||
mAnomalyType = type;
|
||||
@@ -94,6 +122,11 @@ public class AppInfo implements Comparable<AppInfo>, Parcelable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setUid(int uid) {
|
||||
mUid = uid;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AppInfo build() {
|
||||
return new AppInfo(this);
|
||||
}
|
||||
|
||||
@@ -18,12 +18,13 @@ package com.android.settings.fuelgauge.batterytip;
|
||||
|
||||
import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns
|
||||
.ANOMALY_STATE;
|
||||
import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns
|
||||
.PACKAGE_NAME;
|
||||
import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns
|
||||
.ANOMALY_TYPE;
|
||||
import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns
|
||||
.PACKAGE_NAME;
|
||||
import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns
|
||||
.TIME_STAMP_MS;
|
||||
import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns.UID;
|
||||
import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.Tables.TABLE_ANOMALY;
|
||||
|
||||
import android.content.ContentValues;
|
||||
@@ -60,15 +61,17 @@ public class BatteryDatabaseManager {
|
||||
|
||||
/**
|
||||
* Insert an anomaly log to database.
|
||||
* @param packageName the package name of the app
|
||||
* @param type the type of the anomaly
|
||||
* @param anomalyState the state of the anomaly
|
||||
* @param timestampMs the time when it is happened
|
||||
*
|
||||
* @param packageName the package name of the app
|
||||
* @param type the type of the anomaly
|
||||
* @param anomalyState the state of the anomaly
|
||||
* @param timestampMs the time when it is happened
|
||||
*/
|
||||
public synchronized void insertAnomaly(String packageName, int type, int anomalyState,
|
||||
public synchronized void insertAnomaly(int uid, String packageName, int type, int anomalyState,
|
||||
long timestampMs) {
|
||||
try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(UID, uid);
|
||||
values.put(PACKAGE_NAME, packageName);
|
||||
values.put(ANOMALY_TYPE, type);
|
||||
values.put(ANOMALY_STATE, anomalyState);
|
||||
@@ -83,7 +86,7 @@ public class BatteryDatabaseManager {
|
||||
public synchronized List<AppInfo> queryAllAnomalies(long timestampMsAfter, int state) {
|
||||
final List<AppInfo> appInfos = new ArrayList<>();
|
||||
try (SQLiteDatabase db = mDatabaseHelper.getReadableDatabase()) {
|
||||
final String[] projection = {PACKAGE_NAME, ANOMALY_TYPE};
|
||||
final String[] projection = {PACKAGE_NAME, ANOMALY_TYPE, UID};
|
||||
final String orderBy = AnomalyDatabaseHelper.AnomalyColumns.TIME_STAMP_MS + " DESC";
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_ANOMALY, projection,
|
||||
@@ -94,6 +97,7 @@ public class BatteryDatabaseManager {
|
||||
AppInfo appInfo = new AppInfo.Builder()
|
||||
.setPackageName(cursor.getString(cursor.getColumnIndex(PACKAGE_NAME)))
|
||||
.setAnomalyType(cursor.getInt(cursor.getColumnIndex(ANOMALY_TYPE)))
|
||||
.setUid(cursor.getInt(cursor.getColumnIndex(UID)))
|
||||
.build();
|
||||
appInfos.add(appInfo);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ public class HighUsageAdapter extends RecyclerView.Adapter<HighUsageAdapter.View
|
||||
final AppInfo app = mHighUsageAppList.get(position);
|
||||
holder.appIcon.setImageDrawable(
|
||||
Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager, app.packageName,
|
||||
UserHandle.myUserId()));
|
||||
UserHandle.getUserId(app.uid)));
|
||||
holder.appName.setText(Utils.getApplicationLabel(mContext, app.packageName));
|
||||
if (app.screenOnTimeMs != 0) {
|
||||
holder.appTime.setText(StringUtil.formatElapsedTime(mContext, app.screenOnTimeMs, false));
|
||||
|
||||
@@ -73,6 +73,7 @@ public class HighUsageDetector implements BatteryTipDetector {
|
||||
BatteryUtils.StatusType.FOREGROUND, batterySipper.uidObj,
|
||||
BatteryStats.STATS_SINCE_CHARGED);
|
||||
mHighUsageAppList.add(new AppInfo.Builder()
|
||||
.setUid(batterySipper.getUid())
|
||||
.setPackageName(
|
||||
mBatteryUtils.getPackageName(batterySipper.getUid()))
|
||||
.setScreenOnTimeMs(foregroundTimeMs)
|
||||
|
||||
@@ -158,4 +158,9 @@ public abstract class BatteryTip implements Comparable<BatteryTip>, Parcelable {
|
||||
public int compareTo(BatteryTip o) {
|
||||
return TIP_ORDER.get(mType) - TIP_ORDER.get(o.mType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "type=" + mType + " state=" + mState;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +86,19 @@ public class HighUsageTip extends BatteryTip {
|
||||
return mHighUsageAppList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder stringBuilder = new StringBuilder(super.toString());
|
||||
stringBuilder.append(" {");
|
||||
for (int i = 0, size = mHighUsageAppList.size(); i < size; i++) {
|
||||
final AppInfo appInfo = mHighUsageAppList.get(i);
|
||||
stringBuilder.append(" " + appInfo.toString() + " ");
|
||||
}
|
||||
stringBuilder.append('}');
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
|
||||
public BatteryTip createFromParcel(Parcel in) {
|
||||
return new HighUsageTip(in);
|
||||
|
||||
@@ -97,6 +97,19 @@ public class RestrictAppTip extends BatteryTip {
|
||||
return mRestrictAppList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder stringBuilder = new StringBuilder(super.toString());
|
||||
stringBuilder.append(" {");
|
||||
for (int i = 0, size = mRestrictAppList.size(); i < size; i++) {
|
||||
final AppInfo appInfo = mRestrictAppList.get(i);
|
||||
stringBuilder.append(" " + appInfo.toString() + " ");
|
||||
}
|
||||
stringBuilder.append('}');
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
|
||||
@@ -22,7 +22,8 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.Immutable;
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Specifies a setting that is being injected into Settings > Location > Location services.
|
||||
@@ -65,32 +66,19 @@ class InjectedSetting {
|
||||
*/
|
||||
public final String settingsActivity;
|
||||
|
||||
private InjectedSetting(String packageName, String className,
|
||||
String title, int iconId, UserHandle userHandle, String settingsActivity) {
|
||||
this.packageName = Preconditions.checkNotNull(packageName, "packageName");
|
||||
this.className = Preconditions.checkNotNull(className, "className");
|
||||
this.title = Preconditions.checkNotNull(title, "title");
|
||||
this.iconId = iconId;
|
||||
this.mUserHandle = userHandle;
|
||||
this.settingsActivity = Preconditions.checkNotNull(settingsActivity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance, or null.
|
||||
* The user restriction associated with this setting.
|
||||
*/
|
||||
public static InjectedSetting newInstance(String packageName, String className,
|
||||
String title, int iconId, UserHandle userHandle, String settingsActivity) {
|
||||
if (packageName == null || className == null ||
|
||||
TextUtils.isEmpty(title) || TextUtils.isEmpty(settingsActivity)) {
|
||||
if (Log.isLoggable(SettingsInjector.TAG, Log.WARN)) {
|
||||
Log.w(SettingsInjector.TAG, "Illegal setting specification: package="
|
||||
+ packageName + ", class=" + className
|
||||
+ ", title=" + title + ", settingsActivity=" + settingsActivity);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return new InjectedSetting(packageName, className, title, iconId, userHandle,
|
||||
settingsActivity);
|
||||
public final String userRestriction;
|
||||
|
||||
private InjectedSetting(Builder builder) {
|
||||
this.packageName = builder.mPackageName;
|
||||
this.className = builder.mClassName;
|
||||
this.title = builder.mTitle;
|
||||
this.iconId = builder.mIconId;
|
||||
this.mUserHandle = builder.mUserHandle;
|
||||
this.settingsActivity = builder.mSettingsActivity;
|
||||
this.userRestriction = builder.mUserRestriction;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,6 +90,7 @@ class InjectedSetting {
|
||||
", iconId=" + iconId +
|
||||
", userId=" + mUserHandle.getIdentifier() +
|
||||
", settingsActivity='" + settingsActivity + '\'' +
|
||||
", userRestriction='" + userRestriction +
|
||||
'}';
|
||||
}
|
||||
|
||||
@@ -121,10 +110,13 @@ class InjectedSetting {
|
||||
|
||||
InjectedSetting that = (InjectedSetting) o;
|
||||
|
||||
return packageName.equals(that.packageName) && className.equals(that.className)
|
||||
&& title.equals(that.title) && iconId == that.iconId
|
||||
&& mUserHandle.equals(that.mUserHandle)
|
||||
&& settingsActivity.equals(that.settingsActivity);
|
||||
return Objects.equals(packageName, that.packageName)
|
||||
&& Objects.equals(className, that.className)
|
||||
&& Objects.equals(title, that.title)
|
||||
&& Objects.equals(iconId, that.iconId)
|
||||
&& Objects.equals(mUserHandle, that.mUserHandle)
|
||||
&& Objects.equals(settingsActivity, that.settingsActivity)
|
||||
&& Objects.equals(userRestriction, that.userRestriction);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -133,8 +125,67 @@ class InjectedSetting {
|
||||
result = 31 * result + className.hashCode();
|
||||
result = 31 * result + title.hashCode();
|
||||
result = 31 * result + iconId;
|
||||
result = 31 * result + mUserHandle.hashCode();
|
||||
result = 31 * result + (mUserHandle == null ? 0 : mUserHandle.hashCode());
|
||||
result = 31 * result + settingsActivity.hashCode();
|
||||
result = 31 * result + (userRestriction == null ? 0 : userRestriction.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private String mPackageName;
|
||||
private String mClassName;
|
||||
private String mTitle;
|
||||
private int mIconId;
|
||||
private UserHandle mUserHandle;
|
||||
private String mSettingsActivity;
|
||||
private String mUserRestriction;
|
||||
|
||||
public Builder setPackageName(String packageName) {
|
||||
mPackageName = packageName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setClassName(String className) {
|
||||
mClassName = className;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setTitle(String title) {
|
||||
mTitle = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setIconId(int iconId) {
|
||||
mIconId = iconId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setUserHandle(UserHandle userHandle) {
|
||||
mUserHandle = userHandle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSettingsActivity(String settingsActivity) {
|
||||
mSettingsActivity = settingsActivity;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setUserRestriction(String userRestriction) {
|
||||
mUserRestriction = userRestriction;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InjectedSetting build() {
|
||||
if (mPackageName == null || mClassName == null || TextUtils.isEmpty(mTitle)
|
||||
|| TextUtils.isEmpty(mSettingsActivity)) {
|
||||
if (Log.isLoggable(SettingsInjector.TAG, Log.WARN)) {
|
||||
Log.w(SettingsInjector.TAG, "Illegal setting specification: package="
|
||||
+ mPackageName + ", class=" + mClassName
|
||||
+ ", title=" + mTitle + ", settingsActivity=" + mSettingsActivity);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return new InjectedSetting(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.support.v7.preference.PreferenceCategory;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.settings.widget.RestrictedAppPreference;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnPause;
|
||||
@@ -88,7 +89,13 @@ public class LocationServicePreferenceController extends LocationBasePreferenceC
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
mCategoryLocationServices.removeAll();
|
||||
LocationSettings.addPreferencesSorted(getLocationServices(), mCategoryLocationServices);
|
||||
final List<Preference> prefs = getLocationServices();
|
||||
for (Preference pref : prefs) {
|
||||
if (pref instanceof RestrictedAppPreference) {
|
||||
((RestrictedAppPreference) pref).checkRestrictionAndSetDisabled();
|
||||
}
|
||||
}
|
||||
LocationSettings.addPreferencesSorted(prefs, mCategoryLocationServices);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageItemInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
@@ -37,11 +38,14 @@ import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.IconDrawableFactory;
|
||||
import android.util.Log;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.settings.widget.AppPreference;
|
||||
import com.android.settings.widget.RestrictedAppPreference;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
@@ -215,12 +219,21 @@ class SettingsInjector {
|
||||
sa.getResourceId(android.R.styleable.SettingInjectorService_icon, 0);
|
||||
final String settingsActivity =
|
||||
sa.getString(android.R.styleable.SettingInjectorService_settingsActivity);
|
||||
final String userRestriction = sa.getString(
|
||||
android.R.styleable.SettingInjectorService_userRestriction);
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "parsed title: " + title + ", iconId: " + iconId
|
||||
+ ", settingsActivity: " + settingsActivity);
|
||||
}
|
||||
return InjectedSetting.newInstance(packageName, className,
|
||||
title, iconId, userHandle, settingsActivity);
|
||||
return new InjectedSetting.Builder()
|
||||
.setPackageName(packageName)
|
||||
.setClassName(className)
|
||||
.setTitle(title)
|
||||
.setIconId(iconId)
|
||||
.setUserHandle(userHandle)
|
||||
.setSettingsActivity(settingsActivity)
|
||||
.setUserRestriction(userRestriction)
|
||||
.build();
|
||||
} finally {
|
||||
sa.recycle();
|
||||
}
|
||||
@@ -290,15 +303,26 @@ class SettingsInjector {
|
||||
*/
|
||||
private Preference addServiceSetting(Context prefContext, List<Preference> prefs,
|
||||
InjectedSetting info) {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
Drawable appIcon = pm.getDrawable(info.packageName, info.iconId, null);
|
||||
Drawable icon = pm.getUserBadgedIcon(appIcon, info.mUserHandle);
|
||||
Preference pref = new AppPreference(prefContext);
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
Drawable appIcon = null;
|
||||
try {
|
||||
final PackageItemInfo itemInfo = new PackageItemInfo();
|
||||
itemInfo.icon = info.iconId;
|
||||
itemInfo.packageName = info.packageName;
|
||||
final ApplicationInfo appInfo = pm.getApplicationInfo(info.packageName,
|
||||
PackageManager.GET_META_DATA);
|
||||
appIcon = IconDrawableFactory.newInstance(mContext)
|
||||
.getBadgedIcon(itemInfo, appInfo, info.mUserHandle.getIdentifier());
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.e(TAG, "Can't get ApplicationInfo for " + info.packageName, e);
|
||||
}
|
||||
Preference pref = TextUtils.isEmpty(info.userRestriction)
|
||||
? new AppPreference(prefContext)
|
||||
: new RestrictedAppPreference(prefContext, info.userRestriction);
|
||||
pref.setTitle(info.title);
|
||||
pref.setSummary(null);
|
||||
pref.setIcon(icon);
|
||||
pref.setIcon(appIcon);
|
||||
pref.setOnPreferenceClickListener(new ServiceSettingClickedListener(info));
|
||||
|
||||
prefs.add(pref);
|
||||
return pref;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ public class ZenModeBehaviorSettings extends ZenModeSettingsBase implements Inde
|
||||
Lifecycle lifecycle) {
|
||||
List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||
controllers.add(new ZenModeAlarmsPreferenceController(context, lifecycle));
|
||||
controllers.add(new ZenModeMediaSystemOtherPreferenceController(context, lifecycle));
|
||||
controllers.add(new ZenModeMediaPreferenceController(context, lifecycle));
|
||||
controllers.add(new ZenModeSystemPreferenceController(context, lifecycle));
|
||||
controllers.add(new ZenModeEventsPreferenceController(context, lifecycle));
|
||||
controllers.add(new ZenModeRemindersPreferenceController(context, lifecycle));
|
||||
controllers.add(new ZenModeMessagesPreferenceController(context, lifecycle));
|
||||
@@ -85,7 +86,7 @@ public class ZenModeBehaviorSettings extends ZenModeSettingsBase implements Inde
|
||||
public List<String> getNonIndexableKeys(Context context) {
|
||||
final List<String> keys = super.getNonIndexableKeys(context);
|
||||
keys.add(ZenModeAlarmsPreferenceController.KEY);
|
||||
keys.add(ZenModeMediaSystemOtherPreferenceController.KEY);
|
||||
keys.add(ZenModeMediaPreferenceController.KEY);
|
||||
keys.add(ZenModeEventsPreferenceController.KEY);
|
||||
keys.add(ZenModeRemindersPreferenceController.KEY);
|
||||
keys.add(ZenModeMessagesPreferenceController.KEY);
|
||||
|
||||
@@ -25,13 +25,13 @@ import android.util.Log;
|
||||
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
public class ZenModeMediaSystemOtherPreferenceController extends AbstractZenModePreferenceController
|
||||
public class ZenModeMediaPreferenceController extends AbstractZenModePreferenceController
|
||||
implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
protected static final String KEY = "zen_mode_media";
|
||||
private final ZenModeBackend mBackend;
|
||||
|
||||
public ZenModeMediaSystemOtherPreferenceController(Context context, Lifecycle lifecycle) {
|
||||
public ZenModeMediaPreferenceController(Context context, Lifecycle lifecycle) {
|
||||
super(context, KEY, lifecycle);
|
||||
mBackend = ZenModeBackend.getInstance(context);
|
||||
}
|
||||
@@ -63,7 +63,7 @@ public class ZenModeMediaSystemOtherPreferenceController extends AbstractZenMode
|
||||
default:
|
||||
pref.setEnabled(true);
|
||||
pref.setChecked(mBackend.isPriorityCategoryEnabled(
|
||||
Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER));
|
||||
Policy.PRIORITY_CATEGORY_MEDIA));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,9 +71,9 @@ public class ZenModeMediaSystemOtherPreferenceController extends AbstractZenMode
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final boolean allowMedia = (Boolean) newValue;
|
||||
if (ZenModeSettingsBase.DEBUG) {
|
||||
Log.d(TAG, "onPrefChange allowMediaSystemOther=" + allowMedia);
|
||||
Log.d(TAG, "onPrefChange allowMedia=" + allowMedia);
|
||||
}
|
||||
mBackend.saveSoundPolicy(Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER, allowMedia);
|
||||
mBackend.saveSoundPolicy(Policy.PRIORITY_CATEGORY_MEDIA, allowMedia);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -77,9 +77,11 @@ public class ZenModeSettings extends ZenModeSettingsBase {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
// these should match NotificationManager.Policy#ALL_PRIORITY_CATEGORIES
|
||||
private static final int[] ALL_PRIORITY_CATEGORIES = {
|
||||
Policy.PRIORITY_CATEGORY_ALARMS,
|
||||
Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER,
|
||||
Policy.PRIORITY_CATEGORY_MEDIA,
|
||||
Policy.PRIORITY_CATEGORY_SYSTEM,
|
||||
Policy.PRIORITY_CATEGORY_REMINDERS,
|
||||
Policy.PRIORITY_CATEGORY_EVENTS,
|
||||
Policy.PRIORITY_CATEGORY_MESSAGES,
|
||||
@@ -104,10 +106,10 @@ public class ZenModeSettings extends ZenModeSettingsBase {
|
||||
return mContext.getString(R.string.zen_mode_behavior_total_silence);
|
||||
}
|
||||
|
||||
// only alarms and media/system can bypass dnd
|
||||
// only alarms and media can bypass dnd
|
||||
if (numCategories == 2 &&
|
||||
isCategoryEnabled(policy, Policy.PRIORITY_CATEGORY_ALARMS) &&
|
||||
isCategoryEnabled(policy, Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER)) {
|
||||
isCategoryEnabled(policy, Policy.PRIORITY_CATEGORY_MEDIA)) {
|
||||
return mContext.getString(R.string.zen_mode_behavior_alarms_only);
|
||||
}
|
||||
|
||||
@@ -164,9 +166,12 @@ public class ZenModeSettings extends ZenModeSettingsBase {
|
||||
if (isCategoryEnabled(policy, category)) {
|
||||
if (category == Policy.PRIORITY_CATEGORY_ALARMS) {
|
||||
enabledCategories.add(mContext.getString(R.string.zen_mode_alarms));
|
||||
} else if (category == Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER) {
|
||||
} else if (category == Policy.PRIORITY_CATEGORY_MEDIA) {
|
||||
enabledCategories.add(mContext.getString(
|
||||
R.string.zen_mode_media_system_other));
|
||||
R.string.zen_mode_media));
|
||||
} else if (category == Policy.PRIORITY_CATEGORY_SYSTEM) {
|
||||
enabledCategories.add(mContext.getString(
|
||||
R.string.zen_mode_system));
|
||||
} else if (category == Policy.PRIORITY_CATEGORY_REMINDERS) {
|
||||
enabledCategories.add(mContext.getString(R.string.zen_mode_reminders));
|
||||
} else if (category == Policy.PRIORITY_CATEGORY_EVENTS) {
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.notification;
|
||||
|
||||
import android.app.NotificationManager.Policy;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.support.v14.preference.SwitchPreference;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
public class ZenModeSystemPreferenceController extends
|
||||
AbstractZenModePreferenceController implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
protected static final String KEY = "zen_mode_system";
|
||||
|
||||
public ZenModeSystemPreferenceController(Context context, Lifecycle lifecycle) {
|
||||
super(context, KEY, lifecycle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
|
||||
SwitchPreference pref = (SwitchPreference) preference;
|
||||
switch (getZenMode()) {
|
||||
case Settings.Global.ZEN_MODE_NO_INTERRUPTIONS:
|
||||
pref.setEnabled(false);
|
||||
pref.setChecked(false);
|
||||
break;
|
||||
case Settings.Global.ZEN_MODE_ALARMS:
|
||||
pref.setEnabled(false);
|
||||
pref.setChecked(false);
|
||||
break;
|
||||
default:
|
||||
pref.setEnabled(true);
|
||||
pref.setChecked(mBackend.isPriorityCategoryEnabled(
|
||||
Policy.PRIORITY_CATEGORY_SYSTEM));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final boolean allowSystem = (Boolean) newValue;
|
||||
if (ZenModeSettingsBase.DEBUG) {
|
||||
Log.d(TAG, "onPrefChange allowSystem=" + allowSystem);
|
||||
}
|
||||
|
||||
mMetricsFeatureProvider.action(mContext, MetricsProto.MetricsEvent.ACTION_ZEN_ALLOW_SYSTEM,
|
||||
allowSystem);
|
||||
mBackend.saveSoundPolicy(Policy.PRIORITY_CATEGORY_SYSTEM, allowSystem);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -22,10 +22,10 @@ import android.support.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.users.AddUserWhenLockedPreferenceController;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.notification.LockScreenNotificationPreferenceController;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.users.AddUserWhenLockedPreferenceController;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
@@ -130,6 +130,7 @@ public class LockscreenDashboardFragment extends DashboardFragment
|
||||
public List<String> getNonIndexableKeys(Context context) {
|
||||
final List<String> niks = super.getNonIndexableKeys(context);
|
||||
niks.add(KEY_ADD_USER_FROM_LOCK_SCREEN);
|
||||
niks.add(KEY_LOCK_SCREEN_NOTIFICATON_WORK_PROFILE);
|
||||
return niks;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -41,6 +41,7 @@ import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.provider.Settings.Global;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.annotation.WorkerThread;
|
||||
@@ -68,7 +69,6 @@ import com.android.settings.dashboard.SummaryLoader;
|
||||
import com.android.settings.password.ChooseLockGeneric;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.search.Indexable;
|
||||
import com.android.settings.search.SearchIndexableRaw;
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||
import com.android.settingslib.RestrictedPreference;
|
||||
@@ -148,9 +148,6 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
|
||||
private EditUserInfoController mEditUserInfoController = new EditUserInfoController();
|
||||
private AddUserWhenLockedPreferenceController mAddUserWhenLockedPreferenceController;
|
||||
private AutoSyncDataPreferenceController mAutoSyncDataPreferenceController;
|
||||
private AutoSyncPersonalDataPreferenceController mAutoSyncPersonalDataPreferenceController;
|
||||
private AutoSyncWorkDataPreferenceController mAutoSyncWorkDataPreferenceController;
|
||||
|
||||
// A place to cache the generated default avatar
|
||||
private Drawable mDefaultIconDrawable;
|
||||
@@ -159,15 +156,15 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MESSAGE_UPDATE_LIST:
|
||||
updateUserList();
|
||||
break;
|
||||
case MESSAGE_SETUP_USER:
|
||||
onUserCreated(msg.arg1);
|
||||
break;
|
||||
case MESSAGE_CONFIG_USER:
|
||||
onManageUserClicked(msg.arg1, true);
|
||||
break;
|
||||
case MESSAGE_UPDATE_LIST:
|
||||
updateUserList();
|
||||
break;
|
||||
case MESSAGE_SETUP_USER:
|
||||
onUserCreated(msg.arg1);
|
||||
break;
|
||||
case MESSAGE_CONFIG_USER:
|
||||
onManageUserClicked(msg.arg1, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -203,18 +200,9 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
final Context context = getActivity();
|
||||
mAddUserWhenLockedPreferenceController = new AddUserWhenLockedPreferenceController(
|
||||
context, KEY_ADD_USER_WHEN_LOCKED, getLifecycle());
|
||||
|
||||
mAutoSyncDataPreferenceController = new AutoSyncDataPreferenceController(context, this);
|
||||
mAutoSyncPersonalDataPreferenceController =
|
||||
new AutoSyncPersonalDataPreferenceController(context, this);
|
||||
mAutoSyncWorkDataPreferenceController =
|
||||
new AutoSyncWorkDataPreferenceController(context, this);
|
||||
|
||||
final PreferenceScreen screen = getPreferenceScreen();
|
||||
mAddUserWhenLockedPreferenceController.displayPreference(screen);
|
||||
mAutoSyncDataPreferenceController.displayPreference(screen);
|
||||
mAutoSyncPersonalDataPreferenceController.displayPreference(screen);
|
||||
mAutoSyncWorkDataPreferenceController.displayPreference(screen);
|
||||
|
||||
screen.findPreference(mAddUserWhenLockedPreferenceController.getPreferenceKey())
|
||||
.setOnPreferenceChangeListener(mAddUserWhenLockedPreferenceController);
|
||||
|
||||
@@ -275,22 +263,10 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
}
|
||||
final PreferenceScreen screen = getPreferenceScreen();
|
||||
|
||||
if (mAutoSyncDataPreferenceController.isAvailable()) {
|
||||
mAutoSyncDataPreferenceController.updateState(screen.findPreference(
|
||||
mAutoSyncDataPreferenceController.getPreferenceKey()));
|
||||
}
|
||||
if (mAddUserWhenLockedPreferenceController.isAvailable()) {
|
||||
mAddUserWhenLockedPreferenceController.updateState(screen.findPreference(
|
||||
mAddUserWhenLockedPreferenceController.getPreferenceKey()));
|
||||
}
|
||||
if (mAutoSyncPersonalDataPreferenceController.isAvailable()) {
|
||||
mAutoSyncPersonalDataPreferenceController.updateState(screen.findPreference(
|
||||
mAutoSyncPersonalDataPreferenceController.getPreferenceKey()));
|
||||
}
|
||||
if (mAutoSyncWorkDataPreferenceController.isAvailable()) {
|
||||
mAutoSyncWorkDataPreferenceController.updateState(screen.findPreference(
|
||||
mAutoSyncWorkDataPreferenceController.getPreferenceKey()));
|
||||
}
|
||||
|
||||
if (mShouldUpdateUserList) {
|
||||
mUserCaps.updateAddUserCapabilities(getActivity());
|
||||
@@ -330,20 +306,6 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
super.startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(Preference preference) {
|
||||
if (mAutoSyncDataPreferenceController.handlePreferenceTreeClick(preference)) {
|
||||
return true;
|
||||
}
|
||||
if (mAutoSyncPersonalDataPreferenceController.handlePreferenceTreeClick(preference)) {
|
||||
return true;
|
||||
}
|
||||
if (mAutoSyncWorkDataPreferenceController.handlePreferenceTreeClick(preference)) {
|
||||
return true;
|
||||
}
|
||||
return super.onPreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
int pos = 0;
|
||||
@@ -439,16 +401,16 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
synchronized (mUserLock) {
|
||||
if (mRemovingUserId == -1 && !mAddingUser) {
|
||||
switch (userType) {
|
||||
case USER_TYPE_USER:
|
||||
showDialog(DIALOG_ADD_USER);
|
||||
break;
|
||||
case USER_TYPE_RESTRICTED_PROFILE:
|
||||
if (hasLockscreenSecurity()) {
|
||||
addUserNow(USER_TYPE_RESTRICTED_PROFILE);
|
||||
} else {
|
||||
showDialog(DIALOG_NEED_LOCKSCREEN);
|
||||
}
|
||||
break;
|
||||
case USER_TYPE_USER:
|
||||
showDialog(DIALOG_ADD_USER);
|
||||
break;
|
||||
case USER_TYPE_RESTRICTED_PROFILE:
|
||||
if (hasLockscreenSecurity()) {
|
||||
addUserNow(USER_TYPE_RESTRICTED_PROFILE);
|
||||
} else {
|
||||
showDialog(DIALOG_NEED_LOCKSCREEN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -557,9 +519,9 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
}
|
||||
case DIALOG_USER_CANNOT_MANAGE:
|
||||
return new AlertDialog.Builder(context)
|
||||
.setMessage(R.string.user_cannot_manage_message)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.create();
|
||||
.setMessage(R.string.user_cannot_manage_message)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.create();
|
||||
case DIALOG_ADD_USER: {
|
||||
final SharedPreferences preferences = getActivity().getPreferences(
|
||||
Context.MODE_PRIVATE);
|
||||
@@ -571,55 +533,56 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
final int userType = dialogId == DIALOG_ADD_USER
|
||||
? USER_TYPE_USER : USER_TYPE_RESTRICTED_PROFILE;
|
||||
Dialog dlg = new AlertDialog.Builder(context)
|
||||
.setTitle(R.string.user_add_user_title)
|
||||
.setMessage(messageResId)
|
||||
.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
addUserNow(userType);
|
||||
if (!longMessageDisplayed) {
|
||||
preferences.edit().putBoolean(
|
||||
KEY_ADD_USER_LONG_MESSAGE_DISPLAYED, true).apply();
|
||||
}
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
.setTitle(R.string.user_add_user_title)
|
||||
.setMessage(messageResId)
|
||||
.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
addUserNow(userType);
|
||||
if (!longMessageDisplayed) {
|
||||
preferences.edit().putBoolean(
|
||||
KEY_ADD_USER_LONG_MESSAGE_DISPLAYED,
|
||||
true).apply();
|
||||
}
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
return dlg;
|
||||
}
|
||||
case DIALOG_SETUP_USER: {
|
||||
Dialog dlg = new AlertDialog.Builder(context)
|
||||
.setTitle(R.string.user_setup_dialog_title)
|
||||
.setMessage(R.string.user_setup_dialog_message)
|
||||
.setPositiveButton(R.string.user_setup_button_setup_now,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
switchUserNow(mAddedUserId);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.user_setup_button_setup_later, null)
|
||||
.create();
|
||||
.setTitle(R.string.user_setup_dialog_title)
|
||||
.setMessage(R.string.user_setup_dialog_message)
|
||||
.setPositiveButton(R.string.user_setup_button_setup_now,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
switchUserNow(mAddedUserId);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.user_setup_button_setup_later, null)
|
||||
.create();
|
||||
return dlg;
|
||||
}
|
||||
case DIALOG_SETUP_PROFILE: {
|
||||
Dialog dlg = new AlertDialog.Builder(context)
|
||||
.setMessage(R.string.user_setup_profile_dialog_message)
|
||||
.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
switchUserNow(mAddedUserId);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
.setMessage(R.string.user_setup_profile_dialog_message)
|
||||
.setPositiveButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
switchUserNow(mAddedUserId);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create();
|
||||
return dlg;
|
||||
}
|
||||
case DIALOG_CHOOSE_USER_TYPE: {
|
||||
List<HashMap<String, String>> data = new ArrayList<HashMap<String,String>>();
|
||||
HashMap<String,String> addUserItem = new HashMap<String,String>();
|
||||
List<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>();
|
||||
HashMap<String, String> addUserItem = new HashMap<String, String>();
|
||||
addUserItem.put(KEY_TITLE, getString(R.string.user_add_user_item_title));
|
||||
addUserItem.put(KEY_SUMMARY, getString(R.string.user_add_user_item_summary));
|
||||
HashMap<String,String> addProfileItem = new HashMap<String,String>();
|
||||
HashMap<String, String> addProfileItem = new HashMap<String, String>();
|
||||
addProfileItem.put(KEY_TITLE, getString(R.string.user_add_profile_item_title));
|
||||
addProfileItem.put(KEY_SUMMARY, getString(R.string.user_add_profile_item_summary));
|
||||
data.add(addUserItem);
|
||||
@@ -892,7 +855,7 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
// Add a virtual Guest user for guest defaults
|
||||
UserPreference pref = new UserPreference(getPrefContext(), null,
|
||||
UserPreference.USERID_GUEST_DEFAULTS,
|
||||
mUserCaps.mIsAdmin && voiceCapable? this : null /* settings icon handler */,
|
||||
mUserCaps.mIsAdmin && voiceCapable ? this : null /* settings icon handler */,
|
||||
null /* delete icon handler */);
|
||||
pref.setTitle(R.string.user_guest);
|
||||
pref.setIcon(getEncircledDefaultIcon());
|
||||
@@ -1062,20 +1025,20 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
if (v.getTag() instanceof UserPreference) {
|
||||
int userId = ((UserPreference) v.getTag()).getUserId();
|
||||
switch (v.getId()) {
|
||||
case UserPreference.DELETE_ID:
|
||||
final EnforcedAdmin removeDisallowedAdmin =
|
||||
RestrictedLockUtils.checkIfRestrictionEnforced(getContext(),
|
||||
UserManager.DISALLOW_REMOVE_USER, UserHandle.myUserId());
|
||||
if (removeDisallowedAdmin != null) {
|
||||
RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
|
||||
removeDisallowedAdmin);
|
||||
} else {
|
||||
onRemoveUserClicked(userId);
|
||||
}
|
||||
break;
|
||||
case UserPreference.SETTINGS_ID:
|
||||
onManageUserClicked(userId, false);
|
||||
break;
|
||||
case UserPreference.DELETE_ID:
|
||||
final EnforcedAdmin removeDisallowedAdmin =
|
||||
RestrictedLockUtils.checkIfRestrictionEnforced(getContext(),
|
||||
UserManager.DISALLOW_REMOVE_USER, UserHandle.myUserId());
|
||||
if (removeDisallowedAdmin != null) {
|
||||
RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
|
||||
removeDisallowedAdmin);
|
||||
} else {
|
||||
onRemoveUserClicked(userId);
|
||||
}
|
||||
break;
|
||||
case UserPreference.SETTINGS_ID:
|
||||
onManageUserClicked(userId, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1107,8 +1070,9 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
* Returns a default user icon (as a {@link Bitmap}) for the given user.
|
||||
*
|
||||
* Note that for guest users, you should pass in {@code UserHandle.USER_NULL}.
|
||||
*
|
||||
* @param resources resources object to fetch the user icon.
|
||||
* @param userId the user id or {@code UserHandle.USER_NULL} for a non-user specific icon
|
||||
* @param userId the user id or {@code UserHandle.USER_NULL} for a non-user specific icon
|
||||
*/
|
||||
private static Bitmap getDefaultUserIconAsBitmap(Resources resources, int userId) {
|
||||
Bitmap bitmap = null;
|
||||
@@ -1125,6 +1089,7 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
|
||||
/**
|
||||
* Assign the default photo to user with {@paramref userId}
|
||||
*
|
||||
* @param context used to get the {@link UserManager}
|
||||
* @param userId used to get the icon bitmap
|
||||
* @return true if assign photo successfully, false if failed
|
||||
@@ -1161,7 +1126,8 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
um.setUserIcon(userId, icon);
|
||||
try {
|
||||
avatarDataStream.close();
|
||||
} catch (IOException ioe) { }
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
}
|
||||
|
||||
private static class SummaryProvider implements SummaryLoader.SummaryProvider {
|
||||
@@ -1178,49 +1144,49 @@ public class UserSettings extends SettingsPreferenceFragment
|
||||
public void setListening(boolean listening) {
|
||||
if (listening) {
|
||||
UserInfo info = mContext.getSystemService(UserManager.class).getUserInfo(
|
||||
UserHandle.myUserId());
|
||||
UserHandle.myUserId());
|
||||
mSummaryLoader.setSummary(this, mContext.getString(R.string.users_summary,
|
||||
info.name));
|
||||
info.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY =
|
||||
new SummaryLoader.SummaryProviderFactory() {
|
||||
@Override
|
||||
public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity,
|
||||
SummaryLoader summaryLoader) {
|
||||
return new SummaryProvider(activity, summaryLoader);
|
||||
}
|
||||
};
|
||||
(activity, summaryLoader) -> new SummaryProvider(activity, summaryLoader);
|
||||
|
||||
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider() {
|
||||
@Override
|
||||
public List<SearchIndexableRaw> getRawDataToIndex(Context context,
|
||||
boolean enabled) {
|
||||
final List<SearchIndexableRaw> result = new ArrayList<>();
|
||||
final UserCapabilities userCaps = UserCapabilities.create(context);
|
||||
if (!userCaps.mEnabled) {
|
||||
return result;
|
||||
}
|
||||
final Resources res = context.getResources();
|
||||
SearchIndexableRaw data = new SearchIndexableRaw(context);
|
||||
data.title = res.getString(R.string.user_settings_title);
|
||||
data.key = "users_settings";
|
||||
data.screenTitle = res.getString(R.string.user_settings_title);
|
||||
result.add(data);
|
||||
|
||||
if (userCaps.mCanAddUser || userCaps.mDisallowAddUserSetByAdmin) {
|
||||
data = new SearchIndexableRaw(context);
|
||||
data.title = res.getString(userCaps.mCanAddRestrictedProfile ?
|
||||
R.string.user_add_user_or_profile_menu
|
||||
: R.string.user_add_user_menu);
|
||||
data.screenTitle = res.getString(R.string.user_settings_title);
|
||||
data.key = "user_settings_add_users";
|
||||
result.add(data);
|
||||
}
|
||||
return result;
|
||||
@Override
|
||||
protected boolean isPageSearchEnabled(Context context) {
|
||||
final UserCapabilities userCaps = UserCapabilities.create(context);
|
||||
return userCaps.mEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
|
||||
boolean enabled) {
|
||||
final List<SearchIndexableResource> index = new ArrayList<>();
|
||||
// Append the rest of the settings
|
||||
final SearchIndexableResource sir = new SearchIndexableResource(context);
|
||||
sir.xmlResId = R.xml.user_settings;
|
||||
index.add(sir);
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getNonIndexableKeysFromXml(Context context, int xmlResId) {
|
||||
final List<String> niks = super.getNonIndexableKeysFromXml(context, xmlResId);
|
||||
new AddUserWhenLockedPreferenceController(
|
||||
context, KEY_ADD_USER_WHEN_LOCKED, null /* lifecycle */)
|
||||
.updateNonIndexableKeys(niks);
|
||||
new AutoSyncDataPreferenceController(context, null /* parent */)
|
||||
.updateNonIndexableKeys(niks);
|
||||
new AutoSyncPersonalDataPreferenceController(context, null /* parent */)
|
||||
.updateNonIndexableKeys(niks);
|
||||
new AutoSyncWorkDataPreferenceController(context, null /* parent */)
|
||||
.updateNonIndexableKeys(niks);
|
||||
return niks;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
120
src/com/android/settings/widget/RestrictedAppPreference.java
Normal file
120
src/com/android/settings/widget/RestrictedAppPreference.java
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.support.v7.preference.PreferenceManager;
|
||||
import android.support.v7.preference.PreferenceViewHolder;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.RestrictedPreferenceHelper;
|
||||
|
||||
/**
|
||||
* {@link AppPreference} that implements user restriction utilities using
|
||||
* {@link com.android.settingslib.RestrictedPreferenceHelper}.
|
||||
* Used to show policy transparency on {@link AppPreference}.
|
||||
*/
|
||||
public class RestrictedAppPreference extends AppPreference {
|
||||
private RestrictedPreferenceHelper mHelper;
|
||||
private String userRestriction;
|
||||
|
||||
public RestrictedAppPreference(Context context) {
|
||||
super(context);
|
||||
initialize(null, null);
|
||||
}
|
||||
|
||||
public RestrictedAppPreference(Context context, String userRestriction) {
|
||||
super(context);
|
||||
initialize(null, userRestriction);
|
||||
}
|
||||
|
||||
public RestrictedAppPreference(Context context, AttributeSet attrs, String userRestriction) {
|
||||
super(context, attrs);
|
||||
initialize(attrs, userRestriction);
|
||||
}
|
||||
|
||||
private void initialize(AttributeSet attrs, String userRestriction) {
|
||||
setWidgetLayoutResource(R.layout.restricted_icon);
|
||||
mHelper = new RestrictedPreferenceHelper(getContext(), this, attrs);
|
||||
this.userRestriction = userRestriction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
mHelper.onBindViewHolder(holder);
|
||||
final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
|
||||
if (restrictedIcon != null) {
|
||||
restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performClick() {
|
||||
if (!mHelper.performClick()) {
|
||||
super.performClick();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
if (isDisabledByAdmin() && enabled) {
|
||||
return;
|
||||
}
|
||||
super.setEnabled(enabled);
|
||||
}
|
||||
|
||||
public void setDisabledByAdmin(RestrictedLockUtils.EnforcedAdmin admin) {
|
||||
if (mHelper.setDisabledByAdmin(admin)) {
|
||||
notifyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDisabledByAdmin() {
|
||||
return mHelper.isDisabledByAdmin();
|
||||
}
|
||||
|
||||
public void useAdminDisabledSummary(boolean useSummary) {
|
||||
mHelper.useAdminDisabledSummary(useSummary);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
|
||||
mHelper.onAttachedToHierarchy();
|
||||
super.onAttachedToHierarchy(preferenceManager);
|
||||
}
|
||||
|
||||
public void checkRestrictionAndSetDisabled() {
|
||||
if (TextUtils.isEmpty(userRestriction)) {
|
||||
return;
|
||||
}
|
||||
mHelper.checkRestrictionAndSetDisabled(userRestriction, UserHandle.myUserId());
|
||||
}
|
||||
|
||||
public void checkRestrictionAndSetDisabled(String userRestriction) {
|
||||
mHelper.checkRestrictionAndSetDisabled(userRestriction, UserHandle.myUserId());
|
||||
}
|
||||
|
||||
public void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
|
||||
mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
|
||||
}
|
||||
}
|
||||
@@ -24,3 +24,4 @@ com.android.settings.wifi.SavedAccessPointsWifiSettings
|
||||
com.android.settings.notification.ZenModeEventRuleSettings
|
||||
com.android.settings.notification.ZenModeScheduleRuleSettings
|
||||
com.android.settings.fuelgauge.RestrictedAppDetails
|
||||
com.android.settings.datetime.timezone.TimeZoneSettings
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.datetime.timezone;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class BaseTimeZonePreferenceControllerTest {
|
||||
|
||||
private Activity mActivity;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mActivity = Robolectric.setupActivity(Activity.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handlePreferenceTreeClick_correctKey_triggerOnClickListener() {
|
||||
String prefKey = "key1";
|
||||
TestClickListener clickListener = new TestClickListener();
|
||||
TestPreference preference = new TestPreference(mActivity, prefKey);
|
||||
TestPreferenceController controller = new TestPreferenceController(mActivity, prefKey);
|
||||
controller.setOnClickListener(clickListener);
|
||||
|
||||
controller.handlePreferenceTreeClick(preference);
|
||||
assertThat(clickListener.isClicked()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handlePreferenceTreeClick_wrongKey_triggerOnClickListener() {
|
||||
String prefKey = "key1";
|
||||
TestClickListener clickListener = new TestClickListener();
|
||||
TestPreference preference = new TestPreference(mActivity, "wrong_key");
|
||||
TestPreferenceController controller = new TestPreferenceController(mActivity, prefKey);
|
||||
controller.setOnClickListener(clickListener);
|
||||
|
||||
controller.handlePreferenceTreeClick(preference);
|
||||
assertThat(clickListener.isClicked()).isFalse();
|
||||
}
|
||||
|
||||
private static class TestPreferenceController extends BaseTimeZonePreferenceController {
|
||||
|
||||
private final Preference mTestPreference;
|
||||
|
||||
public TestPreferenceController(Context context, String preferenceKey) {
|
||||
super(context, preferenceKey);
|
||||
mTestPreference = new Preference(context);
|
||||
mTestPreference.setKey(preferenceKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestPreference extends Preference {
|
||||
public TestPreference(Context context, String preferenceKey) {
|
||||
super(context);
|
||||
setKey(preferenceKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestClickListener implements OnPreferenceClickListener {
|
||||
|
||||
private boolean isClicked = false;
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
isClicked = true;
|
||||
}
|
||||
|
||||
public boolean isClicked() {
|
||||
return isClicked;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.datetime.timezone;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.icu.util.TimeZone;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class FixedOffsetPreferenceControllerTest {
|
||||
|
||||
private Activity mActivity;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mActivity = Robolectric.setupActivity(Activity.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_matchTimeZoneSummary() {
|
||||
TimeZoneInfo fixedOffsetZone = new TimeZoneInfo.Builder(
|
||||
TimeZone.getFrozenTimeZone("Etc/GMT-8"))
|
||||
.setExemplarLocation("Los Angeles")
|
||||
.setGmtOffset("GMT-08:00")
|
||||
.setItemId(0)
|
||||
.build();
|
||||
Preference preference = new Preference(mActivity);
|
||||
FixedOffsetPreferenceController controller = new FixedOffsetPreferenceController(mActivity);
|
||||
controller.setTimeZoneInfo(fixedOffsetZone);
|
||||
controller.updateState(preference);
|
||||
assertThat(preference.getSummary()).isEqualTo("GMT-08:00");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.datetime.timezone;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class RegionPreferenceControllerTest {
|
||||
|
||||
private Activity mActivity;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mActivity = Robolectric.setupActivity(Activity.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_matchCountryName() {
|
||||
Preference preference = new Preference(mActivity);
|
||||
RegionPreferenceController controller = new RegionPreferenceController(mActivity);
|
||||
controller.setRegionId("US");
|
||||
controller.updateState(preference);
|
||||
assertThat(controller.getSummary()).isEqualTo("United States");
|
||||
assertThat(preference.getSummary()).isEqualTo("United States");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.datetime.timezone;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.icu.util.TimeZone;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class RegionZonePreferenceControllerTest {
|
||||
|
||||
private Activity mActivity;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mActivity = Robolectric.setupActivity(Activity.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_matchTimeZoneName() {
|
||||
TimeZoneInfo tzInfo = new TimeZoneInfo.Builder(
|
||||
TimeZone.getFrozenTimeZone("America/Los_Angeles"))
|
||||
.setGenericName("Pacific Time")
|
||||
.setStandardName("Pacific Standard Time")
|
||||
.setDaylightName("Pacific Daylight Time")
|
||||
.setExemplarLocation("Los Angeles")
|
||||
.setGmtOffset("GMT-08:00")
|
||||
.setItemId(0)
|
||||
.build();
|
||||
Preference preference = new Preference(mActivity);
|
||||
RegionZonePreferenceController controller = new RegionZonePreferenceController(mActivity);
|
||||
controller.setTimeZoneInfo(tzInfo);
|
||||
controller.setClickable(false);
|
||||
controller.updateState(preference);
|
||||
String expectedSummary = "Los Angeles (GMT-08:00)";
|
||||
assertThat(controller.getSummary().toString()).isEqualTo(expectedSummary);
|
||||
assertThat(preference.getSummary().toString()).isEqualTo(expectedSummary);
|
||||
assertThat(preference.isEnabled()).isFalse();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.datetime.timezone;
|
||||
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import com.android.settings.datetime.timezone.TimeZoneInfo.Formatter;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class TimeZoneInfoPreferenceControllerTest {
|
||||
|
||||
@Test
|
||||
public void updateState_matchExpectedFormattedText() {
|
||||
Date now = new Date(0L); // 00:00 1/1/1970
|
||||
Formatter formatter = new Formatter(Locale.US, now);
|
||||
|
||||
TimeZoneInfo timeZoneInfo = formatter.format("America/Los_Angeles");
|
||||
TimeZoneInfoPreferenceController controller =
|
||||
new TimeZoneInfoPreferenceController(RuntimeEnvironment.application, now);
|
||||
controller.setTimeZoneInfo(timeZoneInfo);
|
||||
Preference preference = spy(new Preference(RuntimeEnvironment.application));
|
||||
controller.updateState(preference);
|
||||
assertEquals("Uses Pacific Time (GMT-08:00). "
|
||||
+ "Pacific Daylight Time starts on April 26, 1970.",
|
||||
preference.getTitle().toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.datetime.timezone;
|
||||
|
||||
import com.android.settings.datetime.timezone.model.TimeZoneData;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(shadows = {
|
||||
SettingsShadowResources.class,
|
||||
SettingsShadowResources.SettingsShadowTheme.class,
|
||||
})
|
||||
public class TimeZoneSettingsTest {
|
||||
|
||||
@Test
|
||||
public void findRegionIdForTzId_matchExpectedCountry() {
|
||||
String tzId = "Unknown/Secret_City";
|
||||
TimeZoneData timeZoneData = mock(TimeZoneData.class);
|
||||
when(timeZoneData.lookupCountryCodesForZoneId(tzId))
|
||||
.thenReturn(new HashSet<>(Arrays.asList("US", "GB")));
|
||||
|
||||
TimeZoneSettings settings = new TimeZoneSettings();
|
||||
settings.setTimeZoneData(timeZoneData);
|
||||
assertThat(settings.findRegionIdForTzId(tzId, null, "")).matches("US|GB");
|
||||
assertThat(settings.findRegionIdForTzId(tzId, "GB", "")).isEqualTo("GB");
|
||||
assertThat(settings.findRegionIdForTzId(tzId, null, "GB")).isEqualTo("GB");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPreferenceControllers_matchExpectedControllers() {
|
||||
TimeZoneSettings settings = new TimeZoneSettings();
|
||||
List<AbstractPreferenceController> controllers =
|
||||
settings.createPreferenceControllers(RuntimeEnvironment.application);
|
||||
assertThat(controllers).hasSize(4);
|
||||
assertThat(controllers.get(0)).isInstanceOf(RegionPreferenceController.class);
|
||||
assertThat(controllers.get(1)).isInstanceOf(RegionZonePreferenceController.class);
|
||||
assertThat(controllers.get(2)).isInstanceOf(TimeZoneInfoPreferenceController.class);
|
||||
assertThat(controllers.get(3)).isInstanceOf(FixedOffsetPreferenceController.class);
|
||||
}
|
||||
}
|
||||
@@ -42,8 +42,10 @@ import java.util.List;
|
||||
public class BatteryDatabaseManagerTest {
|
||||
|
||||
private static String PACKAGE_NAME_NEW = "com.android.app1";
|
||||
private static int UID_NEW = 345;
|
||||
private static int TYPE_NEW = 1;
|
||||
private static String PACKAGE_NAME_OLD = "com.android.app2";
|
||||
private static int UID_OLD = 543;
|
||||
private static int TYPE_OLD = 2;
|
||||
private static long NOW = System.currentTimeMillis();
|
||||
private static long ONE_DAY_BEFORE = NOW - DateUtils.DAY_IN_MILLIS;
|
||||
@@ -67,23 +69,23 @@ public class BatteryDatabaseManagerTest {
|
||||
|
||||
@Test
|
||||
public void testAllFunctions() {
|
||||
mBatteryDatabaseManager.insertAnomaly(PACKAGE_NAME_NEW, TYPE_NEW,
|
||||
mBatteryDatabaseManager.insertAnomaly(UID_NEW, PACKAGE_NAME_NEW, TYPE_NEW,
|
||||
AnomalyDatabaseHelper.State.NEW, NOW);
|
||||
mBatteryDatabaseManager.insertAnomaly(PACKAGE_NAME_OLD, TYPE_OLD,
|
||||
mBatteryDatabaseManager.insertAnomaly(UID_OLD, PACKAGE_NAME_OLD, TYPE_OLD,
|
||||
AnomalyDatabaseHelper.State.NEW, TWO_DAYS_BEFORE);
|
||||
|
||||
// In database, it contains two record
|
||||
List<AppInfo> totalAppInfos = mBatteryDatabaseManager.queryAllAnomalies(0 /* timeMsAfter */,
|
||||
AnomalyDatabaseHelper.State.NEW);
|
||||
assertThat(totalAppInfos).hasSize(2);
|
||||
assertAppInfo(totalAppInfos.get(0), PACKAGE_NAME_NEW, TYPE_NEW);
|
||||
assertAppInfo(totalAppInfos.get(1), PACKAGE_NAME_OLD, TYPE_OLD);
|
||||
assertAppInfo(totalAppInfos.get(0), UID_NEW, PACKAGE_NAME_NEW, TYPE_NEW);
|
||||
assertAppInfo(totalAppInfos.get(1), UID_OLD, PACKAGE_NAME_OLD, TYPE_OLD);
|
||||
|
||||
// Only one record shows up if we query by timestamp
|
||||
List<AppInfo> appInfos = mBatteryDatabaseManager.queryAllAnomalies(ONE_DAY_BEFORE,
|
||||
AnomalyDatabaseHelper.State.NEW);
|
||||
assertThat(appInfos).hasSize(1);
|
||||
assertAppInfo(appInfos.get(0), PACKAGE_NAME_NEW, TYPE_NEW);
|
||||
assertAppInfo(appInfos.get(0), UID_NEW, PACKAGE_NAME_NEW, TYPE_NEW);
|
||||
|
||||
mBatteryDatabaseManager.deleteAllAnomaliesBeforeTimeStamp(ONE_DAY_BEFORE);
|
||||
|
||||
@@ -91,14 +93,14 @@ public class BatteryDatabaseManagerTest {
|
||||
List<AppInfo> appInfos1 = mBatteryDatabaseManager.queryAllAnomalies(0 /* timeMsAfter */,
|
||||
AnomalyDatabaseHelper.State.NEW);
|
||||
assertThat(appInfos1).hasSize(1);
|
||||
assertAppInfo(appInfos1.get(0), PACKAGE_NAME_NEW, TYPE_NEW);
|
||||
assertAppInfo(appInfos1.get(0), UID_NEW, PACKAGE_NAME_NEW, TYPE_NEW);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAnomalies_updateSuccessfully() {
|
||||
mBatteryDatabaseManager.insertAnomaly(PACKAGE_NAME_NEW, TYPE_NEW,
|
||||
mBatteryDatabaseManager.insertAnomaly(UID_NEW, PACKAGE_NAME_NEW, TYPE_NEW,
|
||||
AnomalyDatabaseHelper.State.NEW, NOW);
|
||||
mBatteryDatabaseManager.insertAnomaly(PACKAGE_NAME_OLD, TYPE_OLD,
|
||||
mBatteryDatabaseManager.insertAnomaly(UID_OLD, PACKAGE_NAME_OLD, TYPE_OLD,
|
||||
AnomalyDatabaseHelper.State.NEW, NOW);
|
||||
final AppInfo appInfo = new AppInfo.Builder().setPackageName(PACKAGE_NAME_OLD).build();
|
||||
final List<AppInfo> updateAppInfos = new ArrayList<>();
|
||||
@@ -112,17 +114,18 @@ public class BatteryDatabaseManagerTest {
|
||||
List<AppInfo> newAppInfos = mBatteryDatabaseManager.queryAllAnomalies(ONE_DAY_BEFORE,
|
||||
AnomalyDatabaseHelper.State.NEW);
|
||||
assertThat(newAppInfos).hasSize(1);
|
||||
assertAppInfo(newAppInfos.get(0), PACKAGE_NAME_NEW, TYPE_NEW);
|
||||
assertAppInfo(newAppInfos.get(0), UID_NEW, PACKAGE_NAME_NEW, TYPE_NEW);
|
||||
|
||||
// The state of PACKAGE_NAME_OLD is changed to handled
|
||||
List<AppInfo> handledAppInfos = mBatteryDatabaseManager.queryAllAnomalies(ONE_DAY_BEFORE,
|
||||
AnomalyDatabaseHelper.State.HANDLED);
|
||||
assertThat(handledAppInfos).hasSize(1);
|
||||
assertAppInfo(handledAppInfos.get(0), PACKAGE_NAME_OLD, TYPE_OLD);
|
||||
assertAppInfo(handledAppInfos.get(0), UID_OLD, PACKAGE_NAME_OLD, TYPE_OLD);
|
||||
}
|
||||
|
||||
private void assertAppInfo(final AppInfo appInfo, String packageName, int type) {
|
||||
private void assertAppInfo(final AppInfo appInfo, int uid, String packageName, int type) {
|
||||
assertThat(appInfo.packageName).isEqualTo(packageName);
|
||||
assertThat(appInfo.anomalyType).isEqualTo(type);
|
||||
assertThat(appInfo.uid).isEqualTo(uid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ public class BatteryInfoTest {
|
||||
private static final String STATUS_CHARGING_NO_TIME = "50% - charging";
|
||||
private static final String STATUS_CHARGING_TIME = "50% - 0m until fully charged";
|
||||
private static final String STATUS_NOT_CHARGING = "Not charging";
|
||||
private static final int PLUGGED_IN = 1;
|
||||
private static final long REMAINING_TIME_NULL = -1;
|
||||
private static final long REMAINING_TIME = 2;
|
||||
private static final String ENHANCED_STRING_SUFFIX = "based on your usage";
|
||||
@@ -72,6 +71,11 @@ public class BatteryInfoTest {
|
||||
"1m left until fully charged";
|
||||
private static final String TEST_BATTERY_LEVEL_10 = "10%";
|
||||
private static final String FIFTEEN_MIN_FORMATTED = "15m";
|
||||
public static final Estimate DUMMY_ESTIMATE = new Estimate(
|
||||
1000, /* estimateMillis */
|
||||
false, /* isBasedOnUsage */
|
||||
1000 /* averageDischargeTime */);
|
||||
|
||||
private Intent mDisChargingBatteryBroadcast;
|
||||
private Intent mChargingBatteryBroadcast;
|
||||
private Context mContext;
|
||||
@@ -132,14 +136,15 @@ public class BatteryInfoTest {
|
||||
|
||||
@Test
|
||||
public void testGetBatteryInfo_basedOnUsageTrueMoreThanFifteenMinutes_usesCorrectString() {
|
||||
Estimate estimate = new Estimate(Duration.ofHours(4).toMillis(),
|
||||
true /* isBasedOnUsage */,
|
||||
1000 /* averageDischargeTime */);
|
||||
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
|
||||
mBatteryStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */,
|
||||
PowerUtil.convertMsToUs(Duration.ofHours(4).toMillis()),
|
||||
true /* basedOnUsage */);
|
||||
mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000,
|
||||
false /* shortString */);
|
||||
BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
|
||||
mBatteryStats, SystemClock.elapsedRealtime() * 1000, true /* shortString */,
|
||||
PowerUtil.convertMsToUs(Duration.ofHours(4).toMillis()),
|
||||
true /* basedOnUsage */);
|
||||
mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000,
|
||||
true /* shortString */);
|
||||
|
||||
// We only add special mention for the long string
|
||||
assertThat(info.remainingLabel.toString()).contains(ENHANCED_STRING_SUFFIX);
|
||||
@@ -149,14 +154,15 @@ public class BatteryInfoTest {
|
||||
|
||||
@Test
|
||||
public void testGetBatteryInfo_basedOnUsageTrueLessThanSevenMinutes_usesCorrectString() {
|
||||
Estimate estimate = new Estimate(Duration.ofMinutes(7).toMillis(),
|
||||
true /* isBasedOnUsage */,
|
||||
1000 /* averageDischargeTime */);
|
||||
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
|
||||
mBatteryStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */,
|
||||
PowerUtil.convertMsToUs(Duration.ofMinutes(7).toMillis()),
|
||||
true /* basedOnUsage */);
|
||||
mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000,
|
||||
false /* shortString */);
|
||||
BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
|
||||
mBatteryStats, SystemClock.elapsedRealtime() * 1000, true /* shortString */,
|
||||
PowerUtil.convertMsToUs(Duration.ofMinutes(7).toMillis()),
|
||||
true /* basedOnUsage */);
|
||||
mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000,
|
||||
true /* shortString */);
|
||||
|
||||
// These should be identical in either case
|
||||
assertThat(info.remainingLabel.toString()).isEqualTo(
|
||||
@@ -167,10 +173,12 @@ public class BatteryInfoTest {
|
||||
|
||||
@Test
|
||||
public void testGetBatteryInfo_basedOnUsageTrueBetweenSevenAndFifteenMinutes_usesCorrectString() {
|
||||
Estimate estimate = new Estimate(Duration.ofMinutes(10).toMillis(),
|
||||
true /* isBasedOnUsage */,
|
||||
1000 /* averageDischargeTime */);
|
||||
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
|
||||
mBatteryStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */,
|
||||
PowerUtil.convertMsToUs(Duration.ofMinutes(10).toMillis()),
|
||||
true /* basedOnUsage */);
|
||||
mBatteryStats, estimate, SystemClock.elapsedRealtime() * 1000,
|
||||
false /* shortString */);
|
||||
|
||||
// Check that strings are showing less than 15 minutes remaining regardless of exact time.
|
||||
assertThat(info.chargeLabel.toString()).isEqualTo(
|
||||
@@ -184,11 +192,11 @@ public class BatteryInfoTest {
|
||||
@Test
|
||||
public void testGetBatteryInfo_basedOnUsageFalse_usesDefaultString() {
|
||||
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
|
||||
mBatteryStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */,
|
||||
1000, false /* basedOnUsage */);
|
||||
mBatteryStats, DUMMY_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
|
||||
false /* shortString */);
|
||||
BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
|
||||
mBatteryStats, SystemClock.elapsedRealtime() * 1000, true /* shortString */,
|
||||
1000, false /* basedOnUsage */);
|
||||
mBatteryStats, DUMMY_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
|
||||
true /* shortString */);
|
||||
|
||||
assertThat(info.remainingLabel.toString()).doesNotContain(ENHANCED_STRING_SUFFIX);
|
||||
assertThat(info2.remainingLabel.toString()).doesNotContain(ENHANCED_STRING_SUFFIX);
|
||||
@@ -199,8 +207,10 @@ public class BatteryInfoTest {
|
||||
doReturn(TEST_CHARGE_TIME_REMAINING)
|
||||
.when(mBatteryStats)
|
||||
.computeChargeTimeRemaining(anyLong());
|
||||
|
||||
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
|
||||
mBatteryStats, SystemClock.elapsedRealtime() * 1000, false, 1000, false);
|
||||
mBatteryStats, DUMMY_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
|
||||
false /* shortString */);
|
||||
assertThat(info.remainingTimeUs).isEqualTo(TEST_CHARGE_TIME_REMAINING);
|
||||
assertThat(info.remainingLabel.toString())
|
||||
.isEqualTo(TEST_CHARGE_TIME_REMAINING_STRINGIFIED);
|
||||
@@ -211,8 +221,8 @@ public class BatteryInfoTest {
|
||||
mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_LEVEL, 100);
|
||||
|
||||
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
|
||||
mBatteryStats, SystemClock.elapsedRealtime() * 1000, false /* shortString */,
|
||||
1000, false /* basedOnUsage */);
|
||||
mBatteryStats, DUMMY_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
|
||||
false /* shortString */);
|
||||
|
||||
assertThat(info.chargeLabel).isEqualTo("100%");
|
||||
}
|
||||
@@ -296,10 +306,13 @@ public class BatteryInfoTest {
|
||||
} else {
|
||||
doReturn(0L).when(mBatteryStats).computeChargeTimeRemaining(anyLong());
|
||||
}
|
||||
Estimate batteryEstimate = new Estimate(
|
||||
estimate ? 1000 : 0,
|
||||
false /* isBasedOnUsage */,
|
||||
1000 /* averageDischargeTime */);
|
||||
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext,
|
||||
charging ? mChargingBatteryBroadcast : mDisChargingBatteryBroadcast,
|
||||
mBatteryStats, SystemClock.elapsedRealtime() * 1000, false,
|
||||
estimate ? 1000 : 0 /* drainTimeUs */, false);
|
||||
mBatteryStats, batteryEstimate, SystemClock.elapsedRealtime() * 1000, false);
|
||||
doReturn(enhanced).when(mFeatureFactory.powerUsageFeatureProvider)
|
||||
.isEnhancedBatteryPredictionEnabled(mContext);
|
||||
return info;
|
||||
|
||||
@@ -54,6 +54,7 @@ import java.util.List;
|
||||
public class RestrictedAppDetailsTest {
|
||||
|
||||
private static final String PACKAGE_NAME = "com.android.app";
|
||||
private static final int UID = 234;
|
||||
private static final String APP_NAME = "app";
|
||||
|
||||
@Mock
|
||||
@@ -70,60 +71,62 @@ public class RestrictedAppDetailsTest {
|
||||
private InstrumentedPreferenceFragment mFragment;
|
||||
private RestrictedAppDetails mRestrictedAppDetails;
|
||||
private Context mContext;
|
||||
private AppInfo mAppInfo;
|
||||
private Intent mIntent;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mRestrictedAppDetails = spy(new RestrictedAppDetails());
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mRestrictedAppDetails = spy(new RestrictedAppDetails());
|
||||
mAppInfo = new AppInfo.Builder()
|
||||
.setPackageName(PACKAGE_NAME)
|
||||
.setUid(UID)
|
||||
.build();
|
||||
|
||||
when(mRestrictedAppDetails.getPreferenceManager()).thenReturn(mPreferenceManager);
|
||||
when(mPreferenceManager.getContext()).thenReturn(mContext);
|
||||
mRestrictedAppDetails.mPackageManager = mPackageManager;
|
||||
mRestrictedAppDetails.mIconDrawableFactory = mIconDrawableFactory;
|
||||
mRestrictedAppDetails.mAppInfos = new ArrayList<>();
|
||||
mRestrictedAppDetails.mAppInfos.add(new AppInfo.Builder()
|
||||
.setPackageName(PACKAGE_NAME)
|
||||
.build());
|
||||
mRestrictedAppDetails.mRestrictedAppListGroup = spy(new PreferenceCategory(mContext));
|
||||
mRestrictedAppDetails.mBatteryUtils = new BatteryUtils(mContext);
|
||||
when(mRestrictedAppDetails.mRestrictedAppListGroup.getPreferenceManager())
|
||||
.thenReturn(mPreferenceManager);
|
||||
doReturn(mPreferenceManager).when(mRestrictedAppDetails).getPreferenceManager();
|
||||
doReturn(mContext).when(mPreferenceManager).getContext();
|
||||
mRestrictedAppDetails.mPackageManager = mPackageManager;
|
||||
mRestrictedAppDetails.mIconDrawableFactory = mIconDrawableFactory;
|
||||
mRestrictedAppDetails.mAppInfos = new ArrayList<>();
|
||||
mRestrictedAppDetails.mAppInfos.add(mAppInfo);
|
||||
mRestrictedAppDetails.mRestrictedAppListGroup = spy(new PreferenceCategory(mContext));
|
||||
mRestrictedAppDetails.mBatteryUtils = new BatteryUtils(mContext);
|
||||
doReturn(mPreferenceManager).when(
|
||||
mRestrictedAppDetails.mRestrictedAppListGroup).getPreferenceManager();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshUi_displayPreference() throws Exception {
|
||||
doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(PACKAGE_NAME, 0);
|
||||
doReturn(APP_NAME).when(mPackageManager).getApplicationLabel(mApplicationInfo);
|
||||
doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(PACKAGE_NAME, 0);
|
||||
doReturn(APP_NAME).when(mPackageManager).getApplicationLabel(mApplicationInfo);
|
||||
|
||||
mRestrictedAppDetails.refreshUi();
|
||||
mRestrictedAppDetails.refreshUi();
|
||||
|
||||
assertThat(mRestrictedAppDetails.mRestrictedAppListGroup.getPreferenceCount()).isEqualTo(1);
|
||||
final Preference preference = mRestrictedAppDetails.mRestrictedAppListGroup.getPreference(0);
|
||||
assertThat(preference.getKey()).isEqualTo(PACKAGE_NAME);
|
||||
assertThat(preference.getTitle()).isEqualTo(APP_NAME);
|
||||
assertThat(mRestrictedAppDetails.mRestrictedAppListGroup.getPreferenceCount()).isEqualTo(1);
|
||||
final Preference preference = mRestrictedAppDetails.mRestrictedAppListGroup.getPreference(
|
||||
0);
|
||||
assertThat(preference.getTitle()).isEqualTo(APP_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartRestrictedAppDetails_startWithCorrectData() {
|
||||
final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
doAnswer(invocation -> {
|
||||
// Get the intent in which it has the app info bundle
|
||||
mIntent = captor.getValue();
|
||||
return true;
|
||||
}).when(mSettingsActivity).startActivity(captor.capture());
|
||||
final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
doAnswer(invocation -> {
|
||||
// Get the intent in which it has the app info bundle
|
||||
mIntent = captor.getValue();
|
||||
return true;
|
||||
}).when(mSettingsActivity).startActivity(captor.capture());
|
||||
|
||||
RestrictedAppDetails.
|
||||
startRestrictedAppDetails(mSettingsActivity, mFragment, mRestrictedAppDetails.mAppInfos);
|
||||
RestrictedAppDetails.startRestrictedAppDetails(mSettingsActivity, mFragment,
|
||||
mRestrictedAppDetails.mAppInfos);
|
||||
|
||||
final Bundle bundle = mIntent.getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
|
||||
// Verify the bundle has the correct info
|
||||
final List<AppInfo> appInfos =
|
||||
bundle.getParcelableArrayList(RestrictedAppDetails.EXTRA_APP_INFO_LIST);
|
||||
assertThat(appInfos).isNotNull();
|
||||
assertThat(appInfos).hasSize(1);
|
||||
assertThat(appInfos.get(0).packageName).isEqualTo(PACKAGE_NAME);
|
||||
final Bundle bundle = mIntent.getBundleExtra(
|
||||
SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
|
||||
// Verify the bundle has the correct info
|
||||
final List<AppInfo> appInfos = bundle.getParcelableArrayList(
|
||||
RestrictedAppDetails.EXTRA_APP_INFO_LIST);
|
||||
assertThat(appInfos).containsExactly(mAppInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,17 +17,36 @@
|
||||
package com.android.settings.fuelgauge.batterytip;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.robolectric.RuntimeEnvironment.application;
|
||||
|
||||
import android.app.StatsManager;
|
||||
import android.app.job.JobInfo;
|
||||
import android.app.job.JobScheduler;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.StatsDimensionsValue;
|
||||
import android.os.UserManager;
|
||||
|
||||
import com.android.internal.os.BatteryStatsHelper;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.fuelgauge.BatteryUtils;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settingslib.fuelgauge.PowerWhitelistBackend;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.Shadows;
|
||||
import org.robolectric.shadows.ShadowJobScheduler;
|
||||
|
||||
@@ -36,6 +55,37 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class AnomalyDetectionJobServiceTest {
|
||||
private static final int UID = 123;
|
||||
private static final String SYSTEM_PACKAGE = "com.android.system";
|
||||
@Mock
|
||||
private BatteryStatsHelper mBatteryStatsHelper;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
private BatteryDatabaseManager mBatteryDatabaseManager;
|
||||
@Mock
|
||||
private BatteryUtils mBatteryUtils;
|
||||
@Mock
|
||||
private PowerWhitelistBackend mPowerWhitelistBackend;
|
||||
@Mock
|
||||
private StatsDimensionsValue mStatsDimensionsValue;
|
||||
|
||||
private BatteryTipPolicy mPolicy;
|
||||
private Bundle mBundle;
|
||||
private AnomalyDetectionJobService mAnomalyDetectionJobService;
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mPolicy = new BatteryTipPolicy(mContext);
|
||||
mBundle = new Bundle();
|
||||
mBundle.putParcelable(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, mStatsDimensionsValue);
|
||||
|
||||
mAnomalyDetectionJobService = new AnomalyDetectionJobService();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScheduleCleanUp() {
|
||||
@@ -50,4 +100,30 @@ public class AnomalyDetectionJobServiceTest {
|
||||
assertThat(pendingJob.getMaxExecutionDelayMillis())
|
||||
.isEqualTo(TimeUnit.MINUTES.toMillis(30));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveAnomalyToDatabase_systemWhitelisted_doNotSave() {
|
||||
doReturn(SYSTEM_PACKAGE).when(mBatteryUtils).getPackageName(anyInt());
|
||||
doReturn(true).when(mPowerWhitelistBackend).isSysWhitelisted(SYSTEM_PACKAGE);
|
||||
|
||||
mAnomalyDetectionJobService.saveAnomalyToDatabase(mBatteryStatsHelper, mUserManager,
|
||||
mBatteryDatabaseManager, mBatteryUtils, mPolicy, mPowerWhitelistBackend,
|
||||
mContext.getContentResolver(), mBundle);
|
||||
|
||||
verify(mBatteryDatabaseManager, never()).insertAnomaly(anyInt(), anyString(), anyInt(),
|
||||
anyInt(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveAnomalyToDatabase_normalApp_save() {
|
||||
doReturn(SYSTEM_PACKAGE).when(mBatteryUtils).getPackageName(anyInt());
|
||||
doReturn(false).when(mPowerWhitelistBackend).isSysWhitelisted(SYSTEM_PACKAGE);
|
||||
|
||||
mAnomalyDetectionJobService.saveAnomalyToDatabase(mBatteryStatsHelper, mUserManager,
|
||||
mBatteryDatabaseManager, mBatteryUtils, mPolicy, mPowerWhitelistBackend,
|
||||
mContext.getContentResolver(), mBundle);
|
||||
|
||||
verify(mBatteryDatabaseManager).insertAnomaly(anyInt(), anyString(), anyInt(), anyInt(),
|
||||
anyLong());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ public class AppInfoTest {
|
||||
private static final String PACKAGE_NAME = "com.android.app";
|
||||
private static final int ANOMALY_TYPE = Anomaly.AnomalyType.WAKE_LOCK;
|
||||
private static final long SCREEN_TIME_MS = DateUtils.HOUR_IN_MILLIS;
|
||||
private static final int UID = 3452;
|
||||
|
||||
private AppInfo mAppInfo;
|
||||
|
||||
@@ -47,6 +48,7 @@ public class AppInfoTest {
|
||||
.setPackageName(PACKAGE_NAME)
|
||||
.setAnomalyType(ANOMALY_TYPE)
|
||||
.setScreenOnTimeMs(SCREEN_TIME_MS)
|
||||
.setUid(UID)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -61,6 +63,7 @@ public class AppInfoTest {
|
||||
assertThat(appInfo.packageName).isEqualTo(PACKAGE_NAME);
|
||||
assertThat(appInfo.anomalyType).isEqualTo(ANOMALY_TYPE);
|
||||
assertThat(appInfo.screenOnTimeMs).isEqualTo(SCREEN_TIME_MS);
|
||||
assertThat(appInfo.uid).isEqualTo(UID);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -84,5 +87,6 @@ public class AppInfoTest {
|
||||
assertThat(mAppInfo.packageName).isEqualTo(PACKAGE_NAME);
|
||||
assertThat(mAppInfo.anomalyType).isEqualTo(ANOMALY_TYPE);
|
||||
assertThat(mAppInfo.screenOnTimeMs).isEqualTo(SCREEN_TIME_MS);
|
||||
assertThat(mAppInfo.uid).isEqualTo(UID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,10 @@ import android.text.format.DateUtils;
|
||||
import com.android.internal.os.BatterySipper;
|
||||
import com.android.internal.os.BatteryStatsHelper;
|
||||
import com.android.settings.fuelgauge.BatteryUtils;
|
||||
import com.android.settings.fuelgauge.batterytip.AppInfo;
|
||||
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
|
||||
import com.android.settings.fuelgauge.batterytip.HighUsageDataParser;
|
||||
import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -46,7 +48,8 @@ import java.util.List;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class HighUsageDetectorTest {
|
||||
|
||||
private static final int UID = 123;
|
||||
private static final long SCREEN_ON_TIME_MS = DateUtils.HOUR_IN_MILLIS;
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private BatteryStatsHelper mBatteryStatsHelper;
|
||||
@@ -57,6 +60,7 @@ public class HighUsageDetectorTest {
|
||||
@Mock
|
||||
private HighUsageDataParser mDataParser;
|
||||
|
||||
private AppInfo mAppInfo;
|
||||
private BatteryTipPolicy mPolicy;
|
||||
private HighUsageDetector mHighUsageDetector;
|
||||
private List<BatterySipper> mUsageList;
|
||||
@@ -71,6 +75,11 @@ public class HighUsageDetectorTest {
|
||||
mHighUsageDetector.mBatteryUtils = mBatteryUtils;
|
||||
mHighUsageDetector.mDataParser = mDataParser;
|
||||
doNothing().when(mHighUsageDetector).parseBatteryData();
|
||||
doReturn(UID).when(mBatterySipper).getUid();
|
||||
mAppInfo = new AppInfo.Builder()
|
||||
.setUid(UID)
|
||||
.setScreenOnTimeMs(SCREEN_ON_TIME_MS)
|
||||
.build();
|
||||
|
||||
mUsageList = new ArrayList<>();
|
||||
mUsageList.add(mBatterySipper);
|
||||
@@ -87,10 +96,12 @@ public class HighUsageDetectorTest {
|
||||
public void testDetect_containsHighUsageApp_tipVisible() {
|
||||
doReturn(true).when(mDataParser).isDeviceHeavilyUsed();
|
||||
when(mBatteryStatsHelper.getUsageList()).thenReturn(mUsageList);
|
||||
doReturn(DateUtils.HOUR_IN_MILLIS).when(mBatteryUtils).getProcessTimeMs(
|
||||
doReturn(SCREEN_ON_TIME_MS).when(mBatteryUtils).getProcessTimeMs(
|
||||
BatteryUtils.StatusType.FOREGROUND, mBatterySipper.uidObj,
|
||||
BatteryStats.STATS_SINCE_CHARGED);
|
||||
|
||||
assertThat(mHighUsageDetector.detect().isVisible()).isTrue();
|
||||
final HighUsageTip highUsageTip = (HighUsageTip) mHighUsageDetector.detect();
|
||||
assertThat(highUsageTip.isVisible()).isTrue();
|
||||
assertThat(highUsageTip.getHighUsageAppList()).containsExactly(mAppInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class BatteryTipTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildPreference() {
|
||||
public void buildPreference() {
|
||||
final Preference preference = mBatteryTip.buildPreference(mContext);
|
||||
|
||||
assertThat(preference.getTitle()).isEqualTo(TITLE);
|
||||
@@ -61,7 +61,7 @@ public class BatteryTipTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelable() {
|
||||
public void parcelable() {
|
||||
final BatteryTip batteryTip = new TestBatteryTip();
|
||||
|
||||
Parcel parcel = Parcel.obtain();
|
||||
@@ -76,7 +76,7 @@ public class BatteryTipTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTipOrder_orderUnique() {
|
||||
public void tipOrder_orderUnique() {
|
||||
final List<Integer> orders = new ArrayList<>();
|
||||
for (int i = 0, size = BatteryTip.TIP_ORDER.size(); i < size; i++) {
|
||||
orders.add(BatteryTip.TIP_ORDER.valueAt(i));
|
||||
@@ -85,6 +85,11 @@ public class BatteryTipTest {
|
||||
assertThat(orders).containsNoDuplicates();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toString_containBatteryTipData() {
|
||||
assertThat(mBatteryTip.toString()).isEqualTo("type=6 state=0");
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to test the non abstract methods in {@link TestBatteryTip}
|
||||
*/
|
||||
|
||||
@@ -73,4 +73,10 @@ public class HighUsageTipTest {
|
||||
assertThat(app.packageName).isEqualTo(PACKAGE_NAME);
|
||||
assertThat(app.screenOnTimeMs).isEqualTo(SCREEN_TIME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toString_containsAppData() {
|
||||
assertThat(mBatteryTip.toString()).isEqualTo(
|
||||
"type=2 state=0 { packageName=com.android.app,anomalyType=0,screenTime=1800000 }");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public class RestrictAppTipTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelable() {
|
||||
public void parcelable() {
|
||||
Parcel parcel = Parcel.obtain();
|
||||
mNewBatteryTip.writeToParcel(parcel, mNewBatteryTip.describeContents());
|
||||
parcel.setDataPosition(0);
|
||||
@@ -85,40 +85,46 @@ public class RestrictAppTipTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTitle_stateNew_showRestrictTitle() {
|
||||
public void getTitle_stateNew_showRestrictTitle() {
|
||||
assertThat(mNewBatteryTip.getTitle(mContext)).isEqualTo("Restrict 1 app");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTitle_stateHandled_showHandledTitle() {
|
||||
public void getTitle_stateHandled_showHandledTitle() {
|
||||
assertThat(mHandledBatteryTip.getTitle(mContext)).isEqualTo("1 recently restricted");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSummary_stateNew_showRestrictSummary() {
|
||||
public void getSummary_stateNew_showRestrictSummary() {
|
||||
assertThat(mNewBatteryTip.getSummary(mContext))
|
||||
.isEqualTo("app has high battery usage");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSummary_stateHandled_showHandledSummary() {
|
||||
public void getSummary_stateHandled_showHandledSummary() {
|
||||
assertThat(mHandledBatteryTip.getSummary(mContext))
|
||||
.isEqualTo("App changes are in progress");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate_anomalyBecomeInvisible_stateHandled() {
|
||||
public void update_anomalyBecomeInvisible_stateHandled() {
|
||||
mNewBatteryTip.updateState(mInvisibleBatteryTip);
|
||||
|
||||
assertThat(mNewBatteryTip.getState()).isEqualTo(BatteryTip.StateType.HANDLED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate_newAnomalyComes_stateNew() {
|
||||
public void update_newAnomalyComes_stateNew() {
|
||||
mInvisibleBatteryTip.updateState(mNewBatteryTip);
|
||||
assertThat(mInvisibleBatteryTip.getState()).isEqualTo(BatteryTip.StateType.NEW);
|
||||
|
||||
mHandledBatteryTip.updateState(mNewBatteryTip);
|
||||
assertThat(mHandledBatteryTip.getState()).isEqualTo(BatteryTip.StateType.NEW);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toString_containsAppData() {
|
||||
assertThat(mNewBatteryTip.toString()).isEqualTo(
|
||||
"type=1 state=0 { packageName=com.android.app,anomalyType=0,screenTime=0 }");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.location;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public final class InjectedSettingTest {
|
||||
|
||||
private static final String TEST_STRING = "test";
|
||||
|
||||
@Test
|
||||
public void buildWithoutPackageName_ShouldReturnNull() {
|
||||
assertThat(((new InjectedSetting.Builder())
|
||||
.setClassName(TEST_STRING)
|
||||
.setTitle(TEST_STRING)
|
||||
.setSettingsActivity(TEST_STRING).build())).isNull();
|
||||
}
|
||||
|
||||
private InjectedSetting getTestSetting() {
|
||||
return new InjectedSetting.Builder()
|
||||
.setPackageName(TEST_STRING)
|
||||
.setClassName(TEST_STRING)
|
||||
.setTitle(TEST_STRING)
|
||||
.setSettingsActivity(TEST_STRING).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
InjectedSetting setting1 = getTestSetting();
|
||||
InjectedSetting setting2 = getTestSetting();
|
||||
assertThat(setting1).isEqualTo(setting2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHashCode() {
|
||||
InjectedSetting setting = getTestSetting();
|
||||
assertThat(setting.hashCode()).isEqualTo(1225314048);
|
||||
}
|
||||
}
|
||||
@@ -24,16 +24,25 @@ import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.arch.lifecycle.LifecycleOwner;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceCategory;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settings.testutils.shadow.ShadowUserManager;
|
||||
import com.android.settings.widget.RestrictedAppPreference;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -41,11 +50,13 @@ import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(
|
||||
shadows = {
|
||||
ShadowUserManager.class
|
||||
})
|
||||
public class LocationServicePreferenceControllerTest {
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
@@ -56,6 +67,8 @@ public class LocationServicePreferenceControllerTest {
|
||||
private PreferenceScreen mScreen;
|
||||
@Mock
|
||||
private SettingsInjector mSettingsInjector;
|
||||
@Mock
|
||||
private DevicePolicyManager mDevicePolicyManager;
|
||||
|
||||
private Context mContext;
|
||||
private LocationServicePreferenceController mController;
|
||||
@@ -73,6 +86,9 @@ public class LocationServicePreferenceControllerTest {
|
||||
final String key = mController.getPreferenceKey();
|
||||
when(mScreen.findPreference(key)).thenReturn(mCategory);
|
||||
when(mCategory.getKey()).thenReturn(key);
|
||||
when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE))
|
||||
.thenReturn(mDevicePolicyManager);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -132,4 +148,33 @@ public class LocationServicePreferenceControllerTest {
|
||||
|
||||
verify(mSettingsInjector).reloadStatusMessages();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withUserRestriction_shouldDisableLocationAccuracy() {
|
||||
final List<Preference> preferences = new ArrayList<>();
|
||||
final RestrictedAppPreference pref = new RestrictedAppPreference(mContext,
|
||||
UserManager.DISALLOW_CONFIG_LOCATION);
|
||||
pref.setTitle("Location Accuracy");
|
||||
preferences.add(pref);
|
||||
doReturn(preferences).when(mSettingsInjector)
|
||||
.getInjectedSettings(any(Context.class), anyInt());
|
||||
|
||||
int userId = UserHandle.myUserId();
|
||||
List<UserManager.EnforcingUser> enforcingUsers = new ArrayList<>();
|
||||
enforcingUsers.add(new UserManager.EnforcingUser(userId,
|
||||
UserManager.RESTRICTION_SOURCE_DEVICE_OWNER));
|
||||
ComponentName componentName = new ComponentName("test", "test");
|
||||
// Ensure that RestrictedLockUtils.checkIfRestrictionEnforced doesn't return null.
|
||||
ShadowUserManager.getShadow().setUserRestrictionSources(
|
||||
UserManager.DISALLOW_CONFIG_LOCATION,
|
||||
UserHandle.of(userId),
|
||||
enforcingUsers);
|
||||
when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(componentName);
|
||||
|
||||
mController.displayPreference(mScreen);
|
||||
mController.updateState(mCategory);
|
||||
|
||||
assertThat(pref.isEnabled()).isFalse();
|
||||
assertThat(pref.isDisabledByAdmin()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,10 +46,7 @@ import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class ZenModeMediaPreferenceControllerTest {
|
||||
|
||||
private static final boolean MEDIA_SETTINGS = true;
|
||||
|
||||
private ZenModeMediaSystemOtherPreferenceController mController;
|
||||
private ZenModeMediaPreferenceController mController;
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private Context mContext;
|
||||
@@ -75,7 +72,7 @@ public class ZenModeMediaPreferenceControllerTest {
|
||||
mContentResolver = RuntimeEnvironment.application.getContentResolver();
|
||||
when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy);
|
||||
|
||||
mController = new ZenModeMediaSystemOtherPreferenceController(mContext,
|
||||
mController = new ZenModeMediaPreferenceController(mContext,
|
||||
mock(Lifecycle.class));
|
||||
ReflectionHelpers.setField(mController, "mBackend", mBackend);
|
||||
|
||||
@@ -111,13 +108,13 @@ public class ZenModeMediaPreferenceControllerTest {
|
||||
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
|
||||
|
||||
when(mBackend.isPriorityCategoryEnabled(
|
||||
NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER)).
|
||||
thenReturn(MEDIA_SETTINGS);
|
||||
NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA)).
|
||||
thenReturn(true);
|
||||
|
||||
mController.updateState(mockPref);
|
||||
|
||||
verify(mockPref).setEnabled(true);
|
||||
verify(mockPref).setChecked(MEDIA_SETTINGS);
|
||||
verify(mockPref).setChecked(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -126,7 +123,7 @@ public class ZenModeMediaPreferenceControllerTest {
|
||||
mController.onPreferenceChange(mockPref, allow);
|
||||
|
||||
verify(mBackend).saveSoundPolicy(
|
||||
NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER, allow);
|
||||
NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA, allow);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -135,6 +132,6 @@ public class ZenModeMediaPreferenceControllerTest {
|
||||
mController.onPreferenceChange(mockPref, allow);
|
||||
|
||||
verify(mBackend).saveSoundPolicy(
|
||||
NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER, allow);
|
||||
NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA, allow);
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ public class ZenModeSettingsTest {
|
||||
NotificationManager.Policy.PRIORITY_CATEGORY_EVENTS
|
||||
| NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS
|
||||
| NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS
|
||||
| NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER,
|
||||
| NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA,
|
||||
0, 0);
|
||||
final String result = mBuilder.getBehaviorSettingSummary(policy,
|
||||
Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
|
||||
@@ -75,7 +75,7 @@ public class ZenModeSettingsTest {
|
||||
public void testGetBehaviorSettingSummary_alarmsAndMedia() {
|
||||
NotificationManager.Policy policy = new NotificationManager.Policy(
|
||||
NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS
|
||||
| NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER,
|
||||
| NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA,
|
||||
0, 0);
|
||||
final String result = mBuilder.getBehaviorSettingSummary(policy,
|
||||
Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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.notification;
|
||||
|
||||
import static android.provider.Settings.Global.ZEN_MODE;
|
||||
import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
|
||||
import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
|
||||
import static android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.support.v14.preference.SwitchPreference;
|
||||
import android.support.v7.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowApplication;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class ZenModeSystemPreferenceControllerTest {
|
||||
private ZenModeSystemPreferenceController mController;
|
||||
|
||||
@Mock
|
||||
private ZenModeBackend mBackend;
|
||||
@Mock
|
||||
private NotificationManager mNotificationManager;
|
||||
@Mock
|
||||
private SwitchPreference mockPref;
|
||||
@Mock
|
||||
private NotificationManager.Policy mPolicy;
|
||||
@Mock
|
||||
private PreferenceScreen mPreferenceScreen;
|
||||
|
||||
private Context mContext;
|
||||
private ContentResolver mContentResolver;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
ShadowApplication shadowApplication = ShadowApplication.getInstance();
|
||||
shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager);
|
||||
|
||||
mContext = shadowApplication.getApplicationContext();
|
||||
mContentResolver = RuntimeEnvironment.application.getContentResolver();
|
||||
when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy);
|
||||
mController = new ZenModeSystemPreferenceController(mContext, mock(Lifecycle.class));
|
||||
ReflectionHelpers.setField(mController, "mBackend", mBackend);
|
||||
|
||||
when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
|
||||
mockPref);
|
||||
mController.displayPreference(mPreferenceScreen);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_TotalSilence() {
|
||||
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_NO_INTERRUPTIONS);
|
||||
|
||||
final SwitchPreference mockPref = mock(SwitchPreference.class);
|
||||
mController.updateState(mockPref);
|
||||
|
||||
verify(mockPref).setEnabled(false);
|
||||
verify(mockPref).setChecked(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_AlarmsOnly() {
|
||||
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_ALARMS);
|
||||
|
||||
final SwitchPreference mockPref = mock(SwitchPreference.class);
|
||||
mController.updateState(mockPref);
|
||||
|
||||
verify(mockPref).setEnabled(false);
|
||||
verify(mockPref).setChecked(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_Priority() {
|
||||
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
|
||||
|
||||
when(mBackend.isPriorityCategoryEnabled(
|
||||
NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM)).thenReturn(true);
|
||||
|
||||
mController.updateState(mockPref);
|
||||
|
||||
verify(mockPref).setEnabled(true);
|
||||
verify(mockPref).setChecked(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceChanged_EnableSystem() {
|
||||
mController.onPreferenceChange(mockPref, true);
|
||||
|
||||
verify(mBackend).saveSoundPolicy(NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM,
|
||||
true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPreferenceChanged_DisableSystem() {
|
||||
mController.onPreferenceChange(mockPref, false);
|
||||
|
||||
verify(mBackend).saveSoundPolicy(NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM,
|
||||
false);
|
||||
}
|
||||
}
|
||||
@@ -16,16 +16,17 @@
|
||||
|
||||
package com.android.settings.slices;
|
||||
|
||||
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_CONTROLLER;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.os.Bundle;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.settings.core.PreferenceXmlParserUtils;
|
||||
import com.android.settings.core.TogglePreferenceController;
|
||||
import com.android.settings.core.codeinspection.ClassScanner;
|
||||
import com.android.settings.core.codeinspection.CodeInspector;
|
||||
@@ -34,7 +35,6 @@ import com.android.settings.search.DatabaseIndexingUtils;
|
||||
import com.android.settings.search.Indexable;
|
||||
import com.android.settings.search.SearchFeatureProvider;
|
||||
import com.android.settings.search.SearchFeatureProviderImpl;
|
||||
import com.android.settings.core.PreferenceXmlParserUtils;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
@@ -42,8 +42,9 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -53,7 +54,7 @@ import java.util.List;
|
||||
public class SliceControllerInXmlTest {
|
||||
|
||||
private static final List<Class> mSliceControllerClasses = Collections.singletonList(
|
||||
TogglePreferenceController.class
|
||||
TogglePreferenceController.class
|
||||
);
|
||||
|
||||
private final List<String> mXmlDeclaredControllers = new ArrayList<>();
|
||||
@@ -71,7 +72,7 @@ public class SliceControllerInXmlTest {
|
||||
private FakeFeatureFactory mFakeFeatureFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
public void setUp() throws IOException, XmlPullParserException {
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
|
||||
mSearchProvider = new SearchFeatureProviderImpl();
|
||||
@@ -83,44 +84,28 @@ public class SliceControllerInXmlTest {
|
||||
initDeclaredControllers();
|
||||
}
|
||||
|
||||
private void initDeclaredControllers() {
|
||||
private void initDeclaredControllers() throws IOException, XmlPullParserException {
|
||||
final List<Integer> xmlResources = getIndexableXml();
|
||||
XmlResourceParser parser;
|
||||
|
||||
for (int xmlResId : xmlResources) {
|
||||
try {
|
||||
parser = mContext.getResources().getXml(xmlResId);
|
||||
|
||||
int type;
|
||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
&& type != XmlPullParser.START_TAG) {
|
||||
// Parse next until start tag is found
|
||||
final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext,
|
||||
xmlResId, PreferenceXmlParserUtils.MetadataFlag.FLAG_NEED_PREF_CONTROLLER);
|
||||
for (Bundle bundle : metadata) {
|
||||
final String controllerClassName = bundle.getString(METADATA_CONTROLLER);
|
||||
if (TextUtils.isEmpty(controllerClassName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final int outerDepth = parser.getDepth();
|
||||
final AttributeSet attrs = Xml.asAttributeSet(parser);
|
||||
String controllerClassName;
|
||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
|
||||
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
|
||||
continue;
|
||||
}
|
||||
controllerClassName = PreferenceXmlParserUtils.getController(mContext, attrs);
|
||||
|
||||
if (!TextUtils.isEmpty(controllerClassName)) {
|
||||
mXmlDeclaredControllers.add(controllerClassName);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Assume an issue with robolectric resources
|
||||
mXmlDeclaredControllers.add(controllerClassName);
|
||||
}
|
||||
}
|
||||
// We definitely have some controllers in xml, so assert not-empty here as a proxy to
|
||||
// make sure the parser didn't fail
|
||||
assertThat(mXmlDeclaredControllers).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllControllersDeclaredInXml() throws Exception {
|
||||
final List<Class<?>> classes =
|
||||
new ClassScanner().getClassesForPackage(mContext.getPackageName());
|
||||
new ClassScanner().getClassesForPackage(mContext.getPackageName());
|
||||
final List<String> missingControllersInXml = new ArrayList<>();
|
||||
|
||||
for (Class<?> clazz : classes) {
|
||||
@@ -139,7 +124,7 @@ public class SliceControllerInXmlTest {
|
||||
missingControllersInXml.removeAll(mGrandfatheredClasses);
|
||||
|
||||
final String missingControllerError =
|
||||
buildErrorMessage(ERROR_MISSING_CONTROLLER, missingControllersInXml);
|
||||
buildErrorMessage(ERROR_MISSING_CONTROLLER, missingControllersInXml);
|
||||
|
||||
assertWithMessage(missingControllerError).that(missingControllersInXml).isEmpty();
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@ import android.support.test.uiautomator.UiSelector;
|
||||
import android.support.test.uiautomator.Until;
|
||||
import android.system.helpers.SettingsHelper;
|
||||
import android.system.helpers.SettingsHelper.SettingsType;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -102,16 +100,16 @@ public class ZonePickerSettingsTest {
|
||||
// Test 2 time zones with no DST
|
||||
@Test
|
||||
public void testSelectReykjavik() throws Exception {
|
||||
testSelectTimeZone("Iceland", "Reykjavik", "GMT+00:00", "Atlantic/Reykjavik");
|
||||
testSelectTimeZone("Iceland", "Reykjavik", "GMT+00:00", "Atlantic/Reykjavik", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectPhoenix() throws Exception {
|
||||
testSelectTimeZone("United States", "Phoenix", "GMT-07:00", "America/Phoenix");
|
||||
testSelectTimeZone("United States", "Phoenix", "GMT-07:00", "America/Phoenix", false);
|
||||
}
|
||||
|
||||
private void testSelectTimeZone(String region, String timezone, String expectedTimeZoneOffset,
|
||||
String expectedTimeZoneId) throws Exception {
|
||||
String expectedTimeZoneId, boolean assumeOneTimeZoneInRegion) throws Exception {
|
||||
mHelper.setIntSetting(SettingsType.GLOBAL, Settings.Global.AUTO_TIME_ZONE, 0);
|
||||
|
||||
SettingsHelper.launchSettingsPage(
|
||||
@@ -121,16 +119,21 @@ public class ZonePickerSettingsTest {
|
||||
assertTrue(selectTimeZone.isEnabled());
|
||||
selectTimeZone.click();
|
||||
|
||||
// Select region in the dropdown list
|
||||
selectScrollableItem(selectDropDownInSpinner(By.clazz(Spinner.class)),
|
||||
new UiSelector().textContains(region))
|
||||
wait(By.text("Region")).click();
|
||||
// Speed-up the test by searching with the first 2 characters of the region name
|
||||
wait(By.res("android", "search_src_text")).setText(region.substring(0, 2));
|
||||
// Select region in the list
|
||||
selectItemInList(new UiSelector().textContains(region))
|
||||
.click();
|
||||
|
||||
// Select time zone
|
||||
selectScrollableItem(selectTimeZoneList(),
|
||||
new UiSelector().textContains(timezone))
|
||||
.click();
|
||||
// Only select time zone explicitly if there are more than one time zones in a region
|
||||
if (!assumeOneTimeZoneInRegion) {
|
||||
wait(By.text("Time Zone"));
|
||||
selectItemInList(new UiSelector().textContains(timezone))
|
||||
.click();
|
||||
}
|
||||
|
||||
mDevice.pressBack();
|
||||
// The select button should include the GMT offset in the summary
|
||||
BySelector summarySelector = By.res("android:id/summary");
|
||||
UiObject2 selectedTimeZone = selectTimeZone.findObject(summarySelector);
|
||||
@@ -162,21 +165,10 @@ public class ZonePickerSettingsTest {
|
||||
assertEquals(expectedTimeZoneId, TimeZone.getDefault().getID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform click on {@link Spinner} and return the pop-up dropdown list.
|
||||
* @return UiScrollable representing the pop-up dropdown after clicking on the spinner
|
||||
*/
|
||||
private UiScrollable selectDropDownInSpinner(BySelector spinnerSelector)
|
||||
throws UiObjectNotFoundException {
|
||||
UiObject2 spinner = wait(spinnerSelector);
|
||||
spinner.click();
|
||||
|
||||
UiSelector dropDownSelector = new UiSelector().className(ListView.class);
|
||||
return new UiScrollable(dropDownSelector);
|
||||
}
|
||||
|
||||
private UiScrollable selectTimeZoneList() {
|
||||
return new UiScrollable(new UiSelector().resourceId(SETTINGS_PACKAGE + ":id/tz_list"));
|
||||
private UiObject selectItemInList(UiSelector childSelector) throws UiObjectNotFoundException {
|
||||
UiScrollable recyclerView = new UiScrollable(
|
||||
new UiSelector().resourceId(SETTINGS_PACKAGE + ":id/recycler_view"));
|
||||
return selectScrollableItem(recyclerView, childSelector);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user