Snap for 4557233 from aaf307e71d to pi-release

Change-Id: I09f1f870a5e8eb4d49d5385d931689a2ffb7babb
This commit is contained in:
android-build-team Robot
2018-01-21 08:23:50 +00:00
236 changed files with 6505 additions and 2681 deletions

View File

@@ -476,7 +476,7 @@
</intent-filter>
</activity>
<service android:name=".TetherService"
<service android:name=".wifi.tether.TetherService"
android:exported="true"
android:permission="android.permission.TETHER_PRIVILEGED" />

View File

@@ -93,7 +93,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingEnd="8dp"
android:paddingEnd="@dimen/reset_checkbox_padding_end"
android:focusable="false"
android:clickable="false"
android:duplicateParentState="true" />
@@ -104,14 +104,14 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="12dp"
android:textSize="18sp"
android:paddingTop="@dimen/reset_checkbox_title_padding_top"
android:textSize="@dimen/reset_checkbox_title_text_size"
android:text="@string/erase_external_storage" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="4sp"
android:textSize="14sp"
android:paddingTop="@dimen/reset_checkbox_summary_padding_top"
android:textSize="@dimen/reset_checkbox_summary_text_size"
android:text="@string/erase_external_storage_description" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,51 @@
<?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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:focusable="true"
android:clickable="true"
android:visibility="gone">
<CheckBox android:id="@+id/erase_esim"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingEnd="@dimen/reset_checkbox_padding_end"
android:focusable="false"
android:clickable="false"
android:duplicateParentState="true" />
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="vertical">
<TextView android:id="@+id/erase_esim_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/reset_checkbox_title_padding_top"
android:textSize="@dimen/reset_checkbox_title_text_size" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/reset_checkbox_summary_padding_top"
android:textSize="@dimen/reset_checkbox_summary_text_size"
android:text="@string/reset_esim_desc" />
</LinearLayout>
</LinearLayout>

View File

@@ -14,7 +14,8 @@
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
@@ -27,7 +28,8 @@
android:layout_marginTop="12dp"
android:layout_weight="1">
<LinearLayout android:layout_width="match_parent"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
@@ -38,6 +40,11 @@
android:textDirection="locale"
android:text="@string/reset_network_desc" />
<include layout="@layout/reset_esim_checkbox"
android:id="@+id/erase_esim_container"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>

View File

@@ -57,8 +57,6 @@
android:layout_height="wrap_content"
android:paddingTop="20dp"
android:paddingBottom="16dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:scrollbars="none"/>
</LinearLayout>

View File

@@ -21,7 +21,8 @@
android:layout_width="328dp"
android:layout_height="wrap_content"
app:cardUseCompatPadding="true"
app:cardElevation="2dp">
app:cardElevation="2dp"
app:cardCornerRadius="@dimen/suggestion_card_corner_radius">
<LinearLayout
android:layout_width="match_parent"
@@ -38,7 +39,7 @@
android:id="@android:id/icon"
android:layout_width="@dimen/dashboard_tile_image_size"
android:layout_height="@dimen/dashboard_tile_image_size"
android:layout_centerHorizontal = "true"
style="@style/SuggestionCardIcon"
android:layout_marginTop="16dp"
android:layout_marginBottom="8dp" />
@@ -55,21 +56,23 @@
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
style="@style/SuggestionCardText"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:singleLine="true"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:textAppearance="@style/TextAppearance.TileTitle"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
style="@style/SuggestionCardText"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:textAppearance="@style/TextAppearance.SuggestionSummary" />
</LinearLayout>

View File

@@ -21,14 +21,14 @@
android:layout_width="328dp"
android:layout_height="wrap_content"
app:cardUseCompatPadding="true"
app:cardElevation="2dp">
app:cardElevation="2dp"
app:cardCornerRadius="@dimen/suggestion_card_corner_radius">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="112dp"
android:orientation="vertical"
android:background="@android:color/white">
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
@@ -39,7 +39,7 @@
android:id="@android:id/icon"
android:layout_width="@dimen/dashboard_tile_image_size"
android:layout_height="@dimen/dashboard_tile_image_size"
android:layout_centerHorizontal = "true"
style="@style/SuggestionCardIcon"
android:layout_marginTop="16dp"
android:layout_marginBottom="8dp" />
@@ -56,9 +56,11 @@
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
style="@style/SuggestionCardText"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.TileTitle"
android:ellipsize="marquee"
@@ -66,9 +68,11 @@
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
style="@style/SuggestionCardText"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:textAppearance="@style/TextAppearance.SuggestionSummary" />
<Button

View File

@@ -120,6 +120,24 @@
<!-- Whether vibrate_input_devices should be shown or not. -->
<bool name="config_show_vibrate_input_devices">true</bool>
<!-- Whether manage_device_admin should be shown or not. -->
<bool name="config_show_manage_device_admin">true</bool>
<!-- Whether unlock_set_or_change should be shown or not. -->
<bool name="config_show_unlock_set_or_change">true</bool>
<!-- Whether screen_pinning_settings should be shown or not. -->
<bool name="config_show_screen_pinning_settings">true</bool>
<!-- Whether manage_trust_agents should be shown or not. -->
<bool name="config_show_manage_trust_agents">true</bool>
<!-- Whether show_password should be shown or not. -->
<bool name="config_show_show_password">true</bool>
<!-- Whether trust_agent_click_intent should be shown or not. -->
<bool name="config_show_trust_agent_click_intent">true</bool>
<!-- Whether wallpaper attribution should be shown or not. -->
<bool name="config_show_wallpaper_attribution">true</bool>

View File

@@ -300,11 +300,22 @@
<dimen name="suggestion_condition_header_padding_collapsed">10dp</dimen>
<dimen name="suggestion_condition_header_padding_expanded">5dp</dimen>
<!-- Suggestion cards-->
<!-- Suggestion cards size and padding -->
<dimen name="suggestion_card_width_one_card">328dp</dimen>
<dimen name="suggestion_card_width_two_cards">158dp</dimen>
<dimen name="suggestion_card_width_multiple_cards">152dp</dimen>
<dimen name="suggestion_card_margin_end">12dp</dimen>
<dimen name="suggestion_card_outer_margin">16dp</dimen>
<dimen name="suggestion_card_inner_margin">12dp</dimen>
<dimen name="suggestion_card_padding_bottom_one_card">16dp</dimen>
<dimen name="suggestion_card_corner_radius">2dp</dimen>
<dimen name="suggestion_card_title_padding_bottom_one_card">6dp</dimen>
<dimen name="suggestion_card_title_padding_bottom_multiple_cards">8dp</dimen>
<!-- Padding for the reset screens -->
<dimen name="reset_checkbox_padding_end">8dp</dimen>
<dimen name="reset_checkbox_title_padding_top">12dp</dimen>
<dimen name="reset_checkbox_summary_padding_top">4dp</dimen>
<dimen name="reset_checkbox_title_text_size">18sp</dimen>
<dimen name="reset_checkbox_summary_text_size">14sp</dimen>
</resources>

View File

@@ -3213,6 +3213,10 @@
<string name="reset_network_title">Reset Wi-Fi, mobile &amp; Bluetooth</string>
<!-- SD card & phone storage settings screen, message on screen after user selects Reset network settings [CHAR LIMIT=NONE] -->
<string name="reset_network_desc">This will reset all network settings, including:\n\n<li>Wi\u2011Fi</li>\n<li>Mobile data</li>\n<li>Bluetooth</li>"</string>
<!-- SD card & phone storage settings screen, title for the checkbox to let user decide whether erase eSIM data together [CHAR LIMIT=NONE] -->
<string name="reset_esim_title">Also reset eSIMs</string>
<!-- SD card & phone storage settings screen, message for the checkbox to let user decide whether erase eSIM data together [CHAR LIMIT=NONE] -->
<string name="reset_esim_desc">Erase all eSIMs on the phone. You\u2019ll have to contract your carrier to redownload your eSIMs. This will not cancel your mobile service plan.</string>
<!-- SD card & phone storage settings screen, button on screen after user selects Reset network settings -->
<string name="reset_network_button_text">Reset settings</string>
<!-- SD card & phone storage settings screen, message on screen after user selects Reset settings button -->
@@ -3225,6 +3229,10 @@
<string name="network_reset_not_available">Network reset is not available for this user</string>
<!-- Reset settings complete toast text [CHAR LIMIT=75] -->
<string name="reset_network_complete_toast">Network settings have been reset</string>
<!-- Title of the error message shown when error happens during erase eSIM data [CHAR LIMIT=NONE] -->
<string name="reset_esim_error_title">Cant\u2019t reset eSIMs</string>
<!-- Message of the error message shown when error happens during erase eSIM data [CHAR LIMIT=NONE] -->
<string name="reset_esim_error_msg">The eSIMs can\u2019tt be reset due to an error.</string>
<!-- Master Clear -->
<!-- Button title to factory data reset the entire device -->
@@ -6870,6 +6878,9 @@
<!-- Do not disturb: Summary for the zen mode automation option Suggestion. [CHAR LIMIT=NONE] -->
<string name="zen_mode_automation_suggestion_summary">Limit sounds &amp; vibrations at certain times</string>
<!-- Do not disturb: Switch toggle to toggle whether to use an automatic dnd rule or not [CHAR LIMIT=40] -->
<string name="zen_mode_use_automatic_rule">Use rule</string>
<!-- Do not disturb: Zen mode option: Important interruptions [CHAR LIMIT=60] -->
<string name="zen_mode_option_important_interruptions">Priority only</string>
@@ -8677,6 +8688,9 @@
<!-- Notification log debug tool: the word 'none' -->
<string name="notification_log_details_ranking_none">Ranking object doesn\'t contain this key.</string>
<!-- [CHAR_LIMIT=NONE] Developer Settings: Title of the setting which turns on emulation of a display cutout. -->
<string name="display_cutout_emulation">Emulate a display with a cutout</string>
<!-- [CHAR_LIMIT=60] Label for special access screen -->
<string name="special_access">Special app access</string>
@@ -8743,7 +8757,7 @@
<string name="window_trace_quick_settings_title">Window Trace</string>
<!-- [CHAR LIMIT=25] Title of developer tile to toggle layer trace -->
<string name="layer_trace_quick_settings_title">Layer Trace</string>
<string name="layer_trace_quick_settings_title">Surface Trace</string>
<!-- [CHAR LIMIT=60] Title of work profile setting page -->
<string name="managed_profile_settings_title">Work profile settings</string>
@@ -9185,9 +9199,21 @@
<!-- UI debug setting: preference summary - describes the behavior of forcing full raw GNSS satellite measurements [CHAR LIMIT=NONE] -->
<string name="enable_gnss_raw_meas_full_tracking_summary">Track all GNSS constellations and frequencies with no duty cycling</string>
<!-- Title for Storage Access settings -->
<string name="storage_access">Storage access</string>
<!-- Keywords for Storage Access settings -->
<string name="keywords_storage_access">storage access scoped directory</string>
<!-- UI debug setting: preference title - show all crash dialogs [CHAR LIMIT=60] -->
<string name="show_first_crash_dialog">Always show crash dialog</string>
<!-- UI debug setting: preference summary - describes the behavior of showing a dialog every time an app crashes [CHAR LIMIT=NONE] -->
<string name="show_first_crash_dialog_summary">Show dialog every time an app crashes</string>
<!-- Title for Directory Access settings -->
<string name="directory_access">Directory access</string>
<!-- Keywords for Directory Access settings -->
<string name="keywords_directory_access">directory access</string>
<!-- Account type associated with the backup account. Empty for AOSP. [DO NOT TRANSLATE] -->
<string name="account_type"></string>
<!-- Package to target for Account credential confirmation. This will allow users to
remind/rediscover their backup account password prior to a reset. Empty for AOSP.
[DO NOT TRANSLATE] -->
<string name="account_confirmation_package"></string>
</resources>

View File

@@ -323,6 +323,15 @@
<item name="android:textColor">?android:attr/colorAccent</item>
</style>
<style name="SuggestionCardText">
<item name="android:textAlignment">viewStart</item>
</style>
<style name="SuggestionCardIcon">
<item name="android:layout_centerHorizontal">false</item>
<item name="android:layout_alignParentStart">true</item>
</style>
<style name="TextAppearance.SuggestionTitle"
parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:fontFamily">sans-serif-medium</item>

View File

@@ -202,16 +202,6 @@
android:title="@string/wifi_verbose_logging"
android:summary="@string/wifi_verbose_logging_summary"/>
<SwitchPreference
android:key="wifi_aggressive_handover"
android:title="@string/wifi_aggressive_handover"
android:summary="@string/wifi_aggressive_handover_summary"/>
<SwitchPreference
android:key="wifi_allow_scan_with_traffic"
android:title="@string/wifi_allow_scan_with_traffic"
android:summary="@string/wifi_allow_scan_with_traffic_summary"/>
<SwitchPreference
android:key="mobile_data_always_on"
android:title="@string/mobile_data_always_on"
@@ -356,6 +346,10 @@
android:key="density"
android:title="@string/developer_smallest_width" />
<SwitchPreference
android:key="display_cutout_emulation"
android:title="@string/display_cutout_emulation" />
</PreferenceCategory>
<PreferenceCategory android:key="debug_hw_drawing_category"
@@ -459,6 +453,10 @@
android:fragment="com.android.settings.applications.appops.BackgroundCheckSummary"
android:title="@string/background_check_pref" />
<SwitchPreference
android:key="show_first_crash_dialog"
android:title="@string/show_first_crash_dialog"
android:summary="@string/show_first_crash_dialog_summary"/>
<SwitchPreference
android:key="show_all_anrs"

View File

@@ -0,0 +1,24 @@
<?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:title="@string/restricted_app_title">
<PreferenceCategory
android:key="restrict_app_list"/>
</PreferenceScreen>

View File

@@ -158,14 +158,4 @@
android:summary="@string/summary_placeholder"
android:fragment="com.android.settings.security.ScreenPinningSettings" />
<Preference
android:order="90"
android:key="security_misc_usage_access"
android:title="@string/usage_access_title"
android:fragment="com.android.settings.applications.manageapplications.ManageApplications">
<extra
android:name="classname"
android:value="com.android.settings.Settings$UsageAccessSettingsActivity" />
</Preference>
</PreferenceScreen>

View File

@@ -113,13 +113,13 @@
<!-- TODO(b/63720392): add when ready
<Preference
android:key="special_app_storage_access"
android:title="@string/storage_access"
android:key="special_app_directory_access"
android:title="@string/directory_access"
android:fragment="com.android.settings.applications.manageapplications.ManageApplications"
settings:keywords="@string/keywords_storage_access">
settings:keywords="@string/keywords_directory_access">
<extra
android:name="classname"
android:value="com.android.settings.Settings$StorageAccessSettingsActivity" />
android:value="com.android.settings.Settings$DirectoryeAccessSettingsActivity" />
</Preference>
-->

View File

@@ -28,12 +28,6 @@
android:key="zen_automatic_rule_switch"
android:layout="@layout/styled_switch_bar" />
<!-- Rule name -->
<Preference
android:key="rule_name"
android:title="@string/zen_mode_rule_name"
android:persistent="false" />
<!-- During events for -->
<DropDownPreference
android:key="calendar"

View File

@@ -28,12 +28,6 @@
android:key="zen_automatic_rule_switch"
android:layout="@layout/styled_switch_bar" />
<!-- Rule name -->
<Preference
android:key="rule_name"
android:title="@string/zen_mode_rule_name"
android:persistent="false" />
<!-- Days -->
<Preference
android:key="days"

View File

@@ -30,8 +30,8 @@ import android.support.v7.preference.Preference;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.telephony.PhoneStateIntentReceiver;
import com.android.internal.telephony.TelephonyProperties;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.WirelessUtils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
public class AirplaneModeEnabler implements Preference.OnPreferenceChangeListener {

View File

@@ -16,11 +16,12 @@
package com.android.settings;
import static android.provider.Telephony.Carriers.FILTERED_URI;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.provider.Telephony;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.telephony.SubscriptionManager;
@@ -118,7 +119,7 @@ public class ApnPreference extends Preference implements
Context context = getContext();
if (context != null) {
int pos = Integer.parseInt(getKey());
Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
Uri url = ContentUris.withAppendedId(FILTERED_URI, pos);
Intent editIntent = new Intent(Intent.ACTION_EDIT, url);
editIntent.putExtra(ApnSettings.SUB_ID, mSubId);
context.startActivity(editIntent);

View File

@@ -16,6 +16,9 @@
package com.android.settings;
import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
import static android.provider.Telephony.Carriers.FILTERED_URI;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
@@ -39,7 +42,6 @@ import android.os.UserManager;
import android.provider.Telephony;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -50,7 +52,6 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.widget.TextView;
import android.widget.Toast;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -246,6 +247,17 @@ public class ApnSettings extends RestrictedSettingsFragment implements
return null;
}
private boolean isDpcApnEnforced() {
try (Cursor enforceCursor = getContentResolver().query(ENFORCE_MANAGED_URI,
null, null, null, null)) {
if (enforceCursor == null || enforceCursor.getCount() != 1) {
return false;
}
enforceCursor.moveToFirst();
return enforceCursor.getInt(0) > 0;
}
}
private void fillList() {
final TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
final int subId = mSubscriptionInfo != null ? mSubscriptionInfo.getSubscriptionId()
@@ -259,9 +271,9 @@ public class ApnSettings extends RestrictedSettingsFragment implements
where.append(" AND NOT (type='ims')");
}
Cursor cursor = getContentResolver().query(Telephony.Carriers.CONTENT_URI, new String[] {
"_id", "name", "apn", "type", "mvno_type", "mvno_match_data"}, where.toString(),
null, Telephony.Carriers.DEFAULT_SORT_ORDER);
Cursor cursor = getContentResolver().query(FILTERED_URI,
new String[] {"_id", "name", "apn", "type", "mvno_type", "mvno_match_data"},
where.toString(), null, Telephony.Carriers.DEFAULT_SORT_ORDER);
if (cursor != null) {
IccRecords r = null;
@@ -343,15 +355,14 @@ public class ApnSettings extends RestrictedSettingsFragment implements
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (!mUnavailable) {
if (!mUnavailable && !isDpcApnEnforced()) {
if (mAllowAddingApns) {
menu.add(0, MENU_NEW, 0,
getResources().getString(R.string.menu_new))
.setIcon(R.drawable.ic_menu_add_white)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
}
menu.add(0, MENU_RESTORE, 0,
getResources().getString(R.string.menu_restore))
menu.add(0, MENU_RESTORE, 0, getResources().getString(R.string.menu_restore))
.setIcon(android.R.drawable.ic_menu_upload);
}
@@ -387,7 +398,7 @@ public class ApnSettings extends RestrictedSettingsFragment implements
@Override
public boolean onPreferenceTreeClick(Preference preference) {
int pos = Integer.parseInt(preference.getKey());
Uri url = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, pos);
Uri url = ContentUris.withAppendedId(FILTERED_URI, pos);
startActivity(new Intent(Intent.ACTION_EDIT, url));
return true;
}

View File

@@ -49,8 +49,9 @@ import android.widget.Switch;
import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.core.instrumentation.Instrumentable;
import com.android.settings.core.instrumentation.VisibilityLoggerMixin;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import org.xmlpull.v1.XmlPullParserException;
@@ -63,8 +64,7 @@ import java.util.List;
public class DeviceAdminSettings extends ListFragment implements Instrumentable {
static final String TAG = "DeviceAdminSettings";
private final VisibilityLoggerMixin mVisibilityLoggerMixin =
new VisibilityLoggerMixin(getMetricsCategory());
private VisibilityLoggerMixin mVisibilityLoggerMixin;
private DevicePolicyManager mDPM;
private UserManager mUm;
@@ -85,12 +85,6 @@ public class DeviceAdminSettings extends ListFragment implements Instrumentable
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mVisibilityLoggerMixin.onAttach(context);
}
/**
* Internal collection of device admin info objects for all profiles associated with the current
* user.
@@ -121,6 +115,8 @@ public class DeviceAdminSettings extends ListFragment implements Instrumentable
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(),
FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider());
}
@Override

View File

@@ -28,6 +28,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
@@ -39,6 +40,7 @@ import android.os.UserManager;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import android.telephony.euicc.EuiccManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -74,6 +76,7 @@ public class MasterClear extends InstrumentedPreferenceFragment {
private static final String TAG = "MasterClear";
private static final int KEYGUARD_REQUEST = 55;
private static final int CREDENTIAL_CONFIRM_REQUEST = 56;
static final String ERASE_EXTERNAL_EXTRA = "erase_sd";
static final String ERASE_ESIMS_EXTRA = "erase_esim";
@@ -114,7 +117,7 @@ public class MasterClear extends InstrumentedPreferenceFragment {
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode != KEYGUARD_REQUEST) {
if (requestCode != KEYGUARD_REQUEST || requestCode != CREDENTIAL_CONFIRM_REQUEST) {
return;
}
@@ -138,6 +141,33 @@ public class MasterClear extends InstrumentedPreferenceFragment {
args, R.string.master_clear_confirm_title, null, null, 0);
}
@VisibleForTesting
boolean tryShowAccountConfirmation() {
final Context context = getActivity();
final String accountType = context.getString(R.string.account_type);
final String packageName = context.getString(R.string.account_confirmation_package);
if (TextUtils.isEmpty(accountType) || TextUtils.isEmpty(packageName)) {
return false;
}
final AccountManager am = AccountManager.get(context);
Account[] accounts = am.getAccountsByType(accountType);
if (accounts != null && accounts.length > 0) {
final Intent requestAccountConfirmation = new Intent()
.setPackage(packageName)
.setAction("android.accounts.action.PRE_FACTORY_RESET");
// Check to make sure that the intent is supported.
final PackageManager pm = context.getPackageManager();
final List<ResolveInfo> resolutions =
pm.queryIntentActivities(requestAccountConfirmation, 0);
if (resolutions != null && resolutions.size() > 0) {
getActivity().startActivityForResult(
requestAccountConfirmation, CREDENTIAL_CONFIRM_REQUEST);
return true;
}
}
return false;
}
/**
* If the user clicks to begin the reset sequence, we next require a
* keyguard confirmation if the user has currently enabled one. If there
@@ -158,7 +188,10 @@ public class MasterClear extends InstrumentedPreferenceFragment {
.setAction(Intent.ACTION_FACTORY_RESET);
context.startActivity(requestFactoryReset);
}
} else if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
return;
}
if (!tryShowAccountConfirmation() && !runKeyguardConfirmation(KEYGUARD_REQUEST)) {
showFinalConfirmation();
}
}

View File

@@ -18,20 +18,28 @@ package com.android.settings;
import android.annotation.Nullable;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.euicc.EuiccManager;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Spinner;
import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.telephony.PhoneConstants;
@@ -64,6 +72,8 @@ public class ResetNetwork extends InstrumentedPreferenceFragment {
private View mContentView;
private Spinner mSubscriptionSpinner;
private Button mInitiateButton;
private View mEsimContainer;
private CheckBox mEsimCheckbox;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -107,6 +117,7 @@ public class ResetNetwork extends InstrumentedPreferenceFragment {
SubscriptionInfo subscription = mSubscriptions.get(selectedIndex);
args.putInt(PhoneConstants.SUBSCRIPTION_KEY, subscription.getSubscriptionId());
}
args.putBoolean(MasterClear.ERASE_ESIMS_EXTRA, mEsimCheckbox.isChecked());
((SettingsActivity) getActivity()).startPreferencePanel(
this, ResetNetworkConfirm.class.getName(),
args, R.string.reset_network_confirm_title, null, null, 0);
@@ -141,6 +152,8 @@ public class ResetNetwork extends InstrumentedPreferenceFragment {
*/
private void establishInitialState() {
mSubscriptionSpinner = (Spinner) mContentView.findViewById(R.id.reset_network_subscription);
mEsimContainer = mContentView.findViewById(R.id.erase_esim_container);
mEsimCheckbox = mContentView.findViewById(R.id.erase_esim);
mSubscriptions = SubscriptionManager.from(getActivity()).getActiveSubscriptionInfoList();
if (mSubscriptions != null && mSubscriptions.size() > 0) {
@@ -192,6 +205,30 @@ public class ResetNetwork extends InstrumentedPreferenceFragment {
}
mInitiateButton = (Button) mContentView.findViewById(R.id.initiate_reset_network);
mInitiateButton.setOnClickListener(mInitiateListener);
if (showEuiccSettings(getContext())) {
mEsimContainer.setVisibility(View.VISIBLE);
TextView title = mContentView.findViewById(R.id.erase_esim_title);
title.setText(R.string.reset_esim_title);
mEsimContainer.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mEsimCheckbox.toggle();
}
});
} else {
mEsimCheckbox.setChecked(false /* checked */);
}
}
private boolean showEuiccSettings(Context context) {
EuiccManager euiccManager =
(EuiccManager) context.getSystemService(Context.EUICC_SERVICE);
if (!euiccManager.isEnabled()) {
return false;
}
ContentResolver resolver = context.getContentResolver();
return Settings.Global.getInt(resolver, Global.EUICC_PROVISIONED, 0) != 0
|| Settings.Global.getInt(resolver, Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
}
@Override

View File

@@ -16,6 +16,7 @@
package com.android.settings;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.ContentResolver;
@@ -24,9 +25,12 @@ import android.net.ConnectivityManager;
import android.net.NetworkPolicyManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RecoverySystem;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.annotation.VisibleForTesting;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.view.LayoutInflater;
@@ -39,6 +43,7 @@ import com.android.ims.ImsManager;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.telephony.PhoneConstants;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.wrapper.RecoverySystemWrapper;
import com.android.settingslib.RestrictedLockUtils;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
@@ -57,6 +62,43 @@ public class ResetNetworkConfirm extends InstrumentedPreferenceFragment {
private View mContentView;
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@VisibleForTesting boolean mEraseEsim;
@VisibleForTesting EraseEsimAsyncTask mEraseEsimTask;
@VisibleForTesting static RecoverySystemWrapper mRecoverySystem;
/**
* Async task used to erase all the eSIM profiles from the phone. If error happens during
* erasing eSIM profiles or timeout, an error msg is shown.
*/
private static class EraseEsimAsyncTask extends AsyncTask<Void, Void, Boolean> {
private final Context mContext;
private final String mPackageName;
EraseEsimAsyncTask(Context context, String packageName) {
mContext = context;
mPackageName = packageName;
}
@Override
protected Boolean doInBackground(Void... params) {
return mRecoverySystem.wipeEuiccData(
mContext, true /* isWipeEuicc */, mPackageName);
}
@Override
protected void onPostExecute(Boolean succeeded) {
if (succeeded) {
Toast.makeText(mContext, R.string.reset_network_complete_toast, Toast.LENGTH_SHORT)
.show();
} else {
new AlertDialog.Builder(mContext)
.setTitle(R.string.reset_esim_error_title)
.setMessage(R.string.reset_esim_error_msg)
.setPositiveButton(android.R.string.ok, null /* listener */)
.show();
}
}
}
/**
* The user has gone through the multiple confirmation, so now we go ahead
@@ -69,7 +111,8 @@ public class ResetNetworkConfirm extends InstrumentedPreferenceFragment {
if (Utils.isMonkeyRunning()) {
return;
}
// TODO maybe show a progress dialog if this ends up taking a while
// TODO maybe show a progress screen if this ends up taking a while and won't let user
// go back until the tasks finished.
Context context = getActivity();
ConnectivityManager connectivityManager = (ConnectivityManager)
@@ -108,11 +151,20 @@ public class ResetNetworkConfirm extends InstrumentedPreferenceFragment {
ImsManager.factoryReset(context);
restoreDefaultApn(context);
esimFactoryReset(context, context.getPackageName());
}
};
@VisibleForTesting
void esimFactoryReset(Context context, String packageName) {
if (mEraseEsim) {
mEraseEsimTask = new EraseEsimAsyncTask(context, packageName);
mEraseEsimTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
Toast.makeText(context, R.string.reset_network_complete_toast, Toast.LENGTH_SHORT)
.show();
}
};
}
/**
* Restore APN settings to default.
@@ -163,6 +215,16 @@ public class ResetNetworkConfirm extends InstrumentedPreferenceFragment {
if (args != null) {
mSubId = args.getInt(PhoneConstants.SUBSCRIPTION_KEY,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
mEraseEsim = args.getBoolean(MasterClear.ERASE_ESIMS_EXTRA);
}
mRecoverySystem = new RecoverySystemWrapper();
}
@Override
public void onDestroy() {
if (mEraseEsimTask != null) {
mEraseEsimTask.cancel(true /* mayInterruptIfRunning */);
mEraseEsimTask = null;
}
}

View File

@@ -120,7 +120,7 @@ public class Settings extends SettingsActivity {
public static class PhotosStorageActivity extends SettingsActivity {
/* empty */
}
public static class StorageAccessSettingsActivity extends SettingsActivity { /* empty */ }
public static class DirectoryAccessSettingsActivity extends SettingsActivity { /* empty */ }
public static class TopLevelSettings extends SettingsActivity { /* empty */ }
public static class ApnSettingsActivity extends SettingsActivity { /* empty */ }

View File

@@ -56,13 +56,13 @@ import com.android.settings.Settings.WifiSettingsActivity;
import com.android.settings.applications.manageapplications.ManageApplications;
import com.android.settings.backup.BackupSettingsActivity;
import com.android.settings.core.gateway.SettingsGateway;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.core.instrumentation.SharedPreferencesLogger;
import com.android.settings.dashboard.DashboardFeatureProvider;
import com.android.settings.dashboard.DashboardSummary;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.wfd.WifiDisplaySettings;
import com.android.settings.widget.SwitchBar;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.instrumentation.SharedPreferencesLogger;
import com.android.settingslib.development.DevelopmentSettingsEnabler;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.SettingsDrawerActivity;
@@ -92,11 +92,6 @@ public class SettingsActivity extends SettingsDrawerActivity
*/
public static final String EXTRA_SHOW_FRAGMENT = ":settings:show_fragment";
/**
* The metrics category constant for logging source when a setting fragment is opened.
*/
public static final String EXTRA_SOURCE_METRICS_CATEGORY = ":settings:source_metrics";
/**
* When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT},
* this extra can also be specified to supply a Bundle of arguments to pass
@@ -220,7 +215,8 @@ public class SettingsActivity extends SettingsDrawerActivity
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
if (name.equals(getPackageName() + "_preferences")) {
return new SharedPreferencesLogger(this, getMetricsTag());
return new SharedPreferencesLogger(this, getMetricsTag(),
FeatureFactory.getFactory(this).getMetricsFeatureProvider());
}
return super.getSharedPreferences(name, mode);
}

View File

@@ -45,7 +45,6 @@ import android.widget.Button;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.core.instrumentation.Instrumentable;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.search.actionbar.SearchMenuController;
import com.android.settings.support.actionbar.HelpMenuController;
@@ -53,6 +52,7 @@ import com.android.settings.support.actionbar.HelpResourceProvider;
import com.android.settings.widget.LoadingViewController;
import com.android.settingslib.CustomDialogPreference;
import com.android.settingslib.CustomEditTextPreference;
import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.widget.FooterPreferenceMixin;
import java.util.UUID;

View File

@@ -110,6 +110,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.wrapper.DevicePolicyManagerWrapper;
import com.android.settings.wrapper.FingerprintManagerWrapper;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import java.net.InetAddress;
import java.util.ArrayList;
@@ -576,7 +577,7 @@ public final class Utils extends com.android.settingslib.Utils {
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, titleResId);
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, title);
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, isShortcut);
intent.putExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY, sourceMetricsCategory);
intent.putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY, sourceMetricsCategory);
return intent;
}

View File

@@ -51,12 +51,12 @@ import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.SearchIndexableRaw;
import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.accounts.AuthenticatorHelper;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;

View File

@@ -34,11 +34,11 @@ import com.android.settingslib.applications.ApplicationsState.AppFilter;
import java.util.Set;
// TODO(b/63720392): add unit tests
public class AppStateStorageAccessBridge extends AppStateBaseBridge {
public class AppStateDirectoryAccessBridge extends AppStateBaseBridge {
private static final String TAG = "StorageAccessBridge";
private static final String TAG = "DirectoryAccessBridge";
public AppStateStorageAccessBridge(ApplicationsState appState, Callback callback) {
public AppStateDirectoryAccessBridge(ApplicationsState appState, Callback callback) {
super(appState, callback);
}
@@ -48,7 +48,7 @@ public class AppStateStorageAccessBridge extends AppStateBaseBridge {
@Override
protected void updateExtraInfo(AppEntry app, String pkg, int uid) { }
public static final AppFilter FILTER_APP_HAS_STORAGE_ACCESS = new AppFilter() {
public static final AppFilter FILTER_APP_HAS_DIRECTORY_ACCESS = new AppFilter() {
private Set<String> mPackages;

View File

@@ -38,13 +38,13 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
/**
* Detailed settings for an app's storage access permissions (A.K.A Scoped Directory Access).
* Detailed settings for an app's directory access permissions (A.K.A Scoped Directory Access).
*/
// TODO(b/63720392): explain its layout
// TODO(b/63720392): add unit tests
public class StorageAccessDetails extends AppInfoWithHeader implements OnPreferenceChangeListener,
public class DirectoryAccessDetails extends AppInfoWithHeader implements OnPreferenceChangeListener,
OnPreferenceClickListener {
private static final String MY_TAG = "StorageAccessDetails";
private static final String MY_TAG = "DirectoryAccessDetails";
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -105,6 +105,6 @@ public class StorageAccessDetails extends AppInfoWithHeader implements OnPrefere
@Override
public int getMetricsCategory() {
return MetricsEvent.APPLICATIONS_USAGE_ACCESS_DETAIL;
return MetricsEvent.APPLICATIONS_DIRECTORY_ACCESS_DETAIL;
}
}

View File

@@ -44,6 +44,7 @@ import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.core.FeatureFlags;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.widget.AppPreference;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.wrapper.PackageManagerWrapper;
@@ -321,9 +322,13 @@ public class RecentAppsPreferenceController extends AbstractPreferenceController
.setPackage(pkgName);
if (mPm.resolveActivity(launchIntent, 0) == null) {
// Not visible on launcher -> likely not a user visible app, skip
Log.d(TAG, "Not a user visible app, skipping " + pkgName);
return false;
// Not visible on launcher -> likely not a user visible app, skip if non-instant.
final ApplicationsState.AppEntry appEntry =
mApplicationsState.getEntry(pkgName, mUserId);
if (!AppUtils.isInstant(appEntry.info)) {
Log.d(TAG, "Not a user visible or instant app, skipping " + pkgName);
return false;
}
}
return true;
}

View File

@@ -37,8 +37,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.applications.AppStateUsageBridge.UsageState;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
public class UsageAccessDetails extends AppInfoWithHeader implements OnPreferenceChangeListener,
OnPreferenceClickListener {

View File

@@ -93,7 +93,8 @@ public class AppActionButtonPreferenceController extends BasePreferenceControlle
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
return AppUtils.isInstant(mParent.getPackageInfo().applicationInfo)
? DISABLED_FOR_USER : AVAILABLE;
}
@Override

View File

@@ -23,7 +23,7 @@ import com.android.settings.applications.AppStateInstallAppsBridge;
import com.android.settings.applications.AppStateNotificationBridge;
import com.android.settings.applications.AppStateOverlayBridge;
import com.android.settings.applications.AppStatePowerBridge;
import com.android.settings.applications.AppStateStorageAccessBridge;
import com.android.settings.applications.AppStateDirectoryAccessBridge;
import com.android.settings.applications.AppStateUsageBridge;
import com.android.settings.applications.AppStateWriteSettingsBridge;
import com.android.settingslib.applications.ApplicationsState;
@@ -66,7 +66,7 @@ public class AppFilterRegistry {
public static final int FILTER_APPS_WITH_OVERLAY = 10;
public static final int FILTER_APPS_WRITE_SETTINGS = 11;
public static final int FILTER_APPS_INSTALL_SOURCES = 12;
public static final int FILTER_APP_HAS_STORAGE_ACCESS = 13;
public static final int FILTER_APP_HAS_DIRECTORY_ACCESS = 13;
// Next id: 14
private static AppFilterRegistry sRegistry;
@@ -158,10 +158,10 @@ public class AppFilterRegistry {
FILTER_APPS_INSTALL_SOURCES,
R.string.filter_install_sources_apps);
// Apps that interacted with storage access permissions (A.K.A. Scoped Directory Access)
mFilters[FILTER_APP_HAS_STORAGE_ACCESS] = new AppFilterItem(
AppStateStorageAccessBridge.FILTER_APP_HAS_STORAGE_ACCESS,
FILTER_APP_HAS_STORAGE_ACCESS,
// Apps that interacted with directory access permissions (A.K.A. Scoped Directory Access)
mFilters[FILTER_APP_HAS_DIRECTORY_ACCESS] = new AppFilterItem(
AppStateDirectoryAccessBridge.FILTER_APP_HAS_DIRECTORY_ACCESS,
FILTER_APP_HAS_DIRECTORY_ACCESS,
R.string.filter_install_sources_apps);
}
@@ -185,8 +185,8 @@ public class AppFilterRegistry {
return FILTER_APPS_WRITE_SETTINGS;
case ManageApplications.LIST_TYPE_MANAGE_SOURCES:
return FILTER_APPS_INSTALL_SOURCES;
case ManageApplications.LIST_TYPE_STORAGE_ACCESS:
return FILTER_APP_HAS_STORAGE_ACCESS;
case ManageApplications.LIST_TYPE_DIRECTORY_ACCESS:
return FILTER_APP_HAS_DIRECTORY_ACCESS;
default:
return FILTER_APPS_ALL;
}

View File

@@ -84,7 +84,7 @@ import com.android.settings.applications.AppStateInstallAppsBridge;
import com.android.settings.applications.AppStateNotificationBridge;
import com.android.settings.applications.AppStateOverlayBridge;
import com.android.settings.applications.AppStatePowerBridge;
import com.android.settings.applications.AppStateStorageAccessBridge;
import com.android.settings.applications.AppStateDirectoryAccessBridge;
import com.android.settings.applications.AppStateUsageBridge;
import com.android.settings.applications.AppStateUsageBridge.UsageState;
import com.android.settings.applications.AppStateWriteSettingsBridge;
@@ -93,7 +93,7 @@ import com.android.settings.applications.DefaultAppSettings;
import com.android.settings.applications.InstalledAppCounter;
import com.android.settings.applications.InstalledAppDetails;
import com.android.settings.applications.NotificationApps;
import com.android.settings.applications.StorageAccessDetails;
import com.android.settings.applications.DirectoryAccessDetails;
import com.android.settings.applications.UsageAccessDetails;
import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.applications.appinfo.DrawOverlayDetails;
@@ -206,7 +206,7 @@ public class ManageApplications extends InstrumentedPreferenceFragment
public static final int LIST_TYPE_GAMES = 9;
public static final int LIST_TYPE_MOVIES = 10;
public static final int LIST_TYPE_PHOTOGRAPHY = 11;
public static final int LIST_TYPE_STORAGE_ACCESS = 12;
public static final int LIST_TYPE_DIRECTORY_ACCESS = 12;
// List types that should show instant apps.
public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(
@@ -282,9 +282,9 @@ public class ManageApplications extends InstrumentedPreferenceFragment
mListType = LIST_TYPE_PHOTOGRAPHY;
mSortOrder = R.id.sort_order_size;
mStorageType = args.getInt(EXTRA_STORAGE_TYPE, STORAGE_TYPE_DEFAULT);
} else if (className.equals(Settings.StorageAccessSettingsActivity.class.getName())) {
mListType = LIST_TYPE_STORAGE_ACCESS;
screenTitle = R.string.storage_access;
} else if (className.equals(Settings.DirectoryAccessSettingsActivity.class.getName())) {
mListType = LIST_TYPE_DIRECTORY_ACCESS;
screenTitle = R.string.directory_access;
} else {
mListType = LIST_TYPE_MAIN;
}
@@ -449,8 +449,8 @@ public class ManageApplications extends InstrumentedPreferenceFragment
return MetricsEvent.SYSTEM_ALERT_WINDOW_APPS;
case LIST_TYPE_MANAGE_SOURCES:
return MetricsEvent.MANAGE_EXTERNAL_SOURCES;
case LIST_TYPE_STORAGE_ACCESS:
return MetricsEvent.STORAGE_ACCESS;
case LIST_TYPE_DIRECTORY_ACCESS:
return MetricsEvent.DIRECTORY_ACCESS;
default:
return MetricsEvent.VIEW_UNKNOWN;
}
@@ -545,8 +545,8 @@ public class ManageApplications extends InstrumentedPreferenceFragment
case LIST_TYPE_PHOTOGRAPHY:
startAppInfoFragment(AppStorageSettings.class, R.string.storage_photos_videos);
break;
case LIST_TYPE_STORAGE_ACCESS:
startAppInfoFragment(StorageAccessDetails.class, R.string.storage_access);
case LIST_TYPE_DIRECTORY_ACCESS:
startAppInfoFragment(DirectoryAccessDetails.class, R.string.directory_access);
break;
// TODO: Figure out if there is a way where we can spin up the profile's settings
@@ -852,8 +852,8 @@ public class ManageApplications extends InstrumentedPreferenceFragment
mExtraInfoBridge = new AppStateWriteSettingsBridge(mContext, mState, this);
} else if (mManageApplications.mListType == LIST_TYPE_MANAGE_SOURCES) {
mExtraInfoBridge = new AppStateInstallAppsBridge(mContext, mState, this);
} else if (mManageApplications.mListType == LIST_TYPE_STORAGE_ACCESS) {
mExtraInfoBridge = new AppStateStorageAccessBridge(mState, this);
} else if (mManageApplications.mListType == LIST_TYPE_DIRECTORY_ACCESS) {
mExtraInfoBridge = new AppStateDirectoryAccessBridge(mState, this);
} else {
mExtraInfoBridge = null;
}
@@ -1255,7 +1255,7 @@ public class ManageApplications extends InstrumentedPreferenceFragment
case LIST_TYPE_MANAGE_SOURCES:
holder.setSummary(ExternalSourcesDetails.getPreferenceSummary(mContext, entry));
break;
case LIST_TYPE_STORAGE_ACCESS:
case LIST_TYPE_DIRECTORY_ACCESS:
holder.setSummary(null);
break;
default:

View File

@@ -33,10 +33,10 @@ import android.widget.ImageView;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.GearPreference;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;

View File

@@ -23,9 +23,9 @@ import android.support.v7.preference.Preference;
import android.text.TextUtils;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class BluetoothDeviceRenamePreferenceController extends

View File

@@ -27,12 +27,12 @@ import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.widget.SwitchWidgetController;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.WirelessUtils;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
/**
* BluetoothEnabler is a helper to manage the Bluetooth on/off checkbox

View File

@@ -23,9 +23,9 @@ import android.support.v7.preference.Preference;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
/**
* Controller that shows received files

View File

@@ -16,8 +16,9 @@
package com.android.settings.core;
import com.android.settings.core.instrumentation.Instrumentable;
import com.android.settings.core.instrumentation.VisibilityLoggerMixin;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.core.lifecycle.ObservableActivity;
/**
@@ -27,7 +28,8 @@ public abstract class InstrumentedActivity extends ObservableActivity implements
public InstrumentedActivity() {
// Mixin that logs visibility change for activity.
getLifecycle().addObserver(new VisibilityLoggerMixin(getMetricsCategory()));
getLifecycle().addObserver(new VisibilityLoggerMixin(getMetricsCategory(),
FeatureFactory.getFactory(this).getMetricsFeatureProvider()));
}
}

View File

@@ -18,30 +18,28 @@ package com.android.settings.core;
import android.content.Context;
import com.android.settings.core.instrumentation.Instrumentable;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.core.instrumentation.VisibilityLoggerMixin;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.survey.SurveyMixin;
import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.core.lifecycle.ObservableFragment;
public abstract class InstrumentedFragment extends ObservableFragment implements Instrumentable {
protected MetricsFeatureProvider mMetricsFeatureProvider;
private final VisibilityLoggerMixin mVisibilityLoggerMixin;
public InstrumentedFragment() {
// Mixin that logs visibility change for activity.
mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory());
getLifecycle().addObserver(mVisibilityLoggerMixin);
getLifecycle().addObserver(new SurveyMixin(this, getClass().getSimpleName()));
}
private VisibilityLoggerMixin mVisibilityLoggerMixin;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(),
mMetricsFeatureProvider);
// Mixin that logs visibility change for activity.
getLifecycle().addObserver(mVisibilityLoggerMixin);
getLifecycle().addObserver(new SurveyMixin(this, getClass().getSimpleName()));
super.onAttach(context);
}
@Override

View File

@@ -23,11 +23,11 @@ import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;
import android.util.Log;
import com.android.settings.core.instrumentation.Instrumentable;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.core.instrumentation.VisibilityLoggerMixin;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.survey.SurveyMixin;
import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment;
/**
@@ -44,19 +44,17 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc
// metrics placeholder value. Only use this for development.
protected final int PLACEHOLDER_METRIC = 10000;
private final VisibilityLoggerMixin mVisibilityLoggerMixin;
public InstrumentedPreferenceFragment() {
// Mixin that logs visibility change for activity.
mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory());
getLifecycle().addObserver(mVisibilityLoggerMixin);
getLifecycle().addObserver(new SurveyMixin(this, getClass().getSimpleName()));
}
private VisibilityLoggerMixin mVisibilityLoggerMixin;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
// Mixin that logs visibility change for activity.
mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(),
mMetricsFeatureProvider);
getLifecycle().addObserver(mVisibilityLoggerMixin);
getLifecycle().addObserver(new SurveyMixin(this, getClass().getSimpleName()));
super.onAttach(context);
}
@Override

View File

@@ -44,7 +44,7 @@ import com.android.settings.applications.ManageDomainUrls;
import com.android.settings.applications.NotificationApps;
import com.android.settings.applications.ProcessStatsSummary;
import com.android.settings.applications.ProcessStatsUi;
import com.android.settings.applications.StorageAccessDetails;
import com.android.settings.applications.DirectoryAccessDetails;
import com.android.settings.applications.UsageAccessDetails;
import com.android.settings.applications.VrListenerSettings;
import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
@@ -254,7 +254,7 @@ public class SettingsGateway {
LockscreenDashboardFragment.class.getName(),
BluetoothDeviceDetailsFragment.class.getName(),
DataUsageList.class.getName(),
StorageAccessDetails.class.getName()
DirectoryAccessDetails.class.getName()
};
public static final String[] SETTINGS_FOR_RESTRICTED = {

View File

@@ -1,110 +0,0 @@
/*
* Copyright (C) 2016 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.core.instrumentation;
import android.content.Context;
import android.metrics.LogMaker;
import android.util.Log;
import android.util.Pair;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
/**
* {@link LogWriter} that writes data to eventlog.
*/
public class EventLogWriter implements LogWriter {
private final MetricsLogger mMetricsLogger = new MetricsLogger();
public void visible(Context context, int source, int category) {
final LogMaker logMaker = new LogMaker(category)
.setType(MetricsProto.MetricsEvent.TYPE_OPEN)
.addTaggedData(MetricsProto.MetricsEvent.FIELD_CONTEXT, source);
MetricsLogger.action(logMaker);
}
public void hidden(Context context, int category) {
MetricsLogger.hidden(context, category);
}
public void action(int category, int value, Pair<Integer, Object>... taggedData) {
if (taggedData == null || taggedData.length == 0) {
mMetricsLogger.action(category, value);
} else {
final LogMaker logMaker = new LogMaker(category)
.setType(MetricsProto.MetricsEvent.TYPE_ACTION)
.setSubtype(value);
for (Pair<Integer, Object> pair : taggedData) {
logMaker.addTaggedData(pair.first, pair.second);
}
mMetricsLogger.write(logMaker);
}
}
public void action(int category, boolean value, Pair<Integer, Object>... taggedData) {
action(category, value ? 1 : 0, taggedData);
}
public void action(Context context, int category, Pair<Integer, Object>... taggedData) {
action(context, category, "", taggedData);
}
public void actionWithSource(Context context, int source, int category) {
final LogMaker logMaker = new LogMaker(category)
.setType(MetricsProto.MetricsEvent.TYPE_ACTION);
if (source != MetricsProto.MetricsEvent.VIEW_UNKNOWN) {
logMaker.addTaggedData(MetricsProto.MetricsEvent.FIELD_CONTEXT, source);
}
MetricsLogger.action(logMaker);
}
/** @deprecated use {@link #action(int, int, Pair[])} */
@Deprecated
public void action(Context context, int category, int value) {
MetricsLogger.action(context, category, value);
}
/** @deprecated use {@link #action(int, boolean, Pair[])} */
@Deprecated
public void action(Context context, int category, boolean value) {
MetricsLogger.action(context, category, value);
}
public void action(Context context, int category, String pkg,
Pair<Integer, Object>... taggedData) {
if (taggedData == null || taggedData.length == 0) {
MetricsLogger.action(context, category, pkg);
} else {
final LogMaker logMaker = new LogMaker(category)
.setType(MetricsProto.MetricsEvent.TYPE_ACTION)
.setPackageName(pkg);
for (Pair<Integer, Object> pair : taggedData) {
logMaker.addTaggedData(pair.first, pair.second);
}
MetricsLogger.action(logMaker);
}
}
public void count(Context context, String name, int value) {
MetricsLogger.count(context, name, value);
}
public void histogram(Context context, String name, int bucket) {
MetricsLogger.histogram(context, name, bucket);
}
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright (C) 2016 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.core.instrumentation;
public interface Instrumentable {
int METRICS_CATEGORY_UNKNOWN = 0;
/**
* Instrumented name for a view as defined in
* {@link com.android.internal.logging.nano.MetricsProto.MetricsEvent}.
*/
int getMetricsCategory();
}

View File

@@ -19,6 +19,9 @@ import android.content.Context;
import com.android.settings.DialogCreatable;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.core.lifecycle.ObservableDialogFragment;
public abstract class InstrumentedDialogFragment extends ObservableDialogFragment
@@ -38,13 +41,15 @@ public abstract class InstrumentedDialogFragment extends ObservableDialogFragmen
public InstrumentedDialogFragment(DialogCreatable dialogCreatable, int dialogId) {
mDialogCreatable = dialogCreatable;
mDialogId = dialogId;
mLifecycle.addObserver(new VisibilityLoggerMixin(getMetricsCategory()));
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
mMetricsFeatureProvider = FeatureFactory.getFactory(context)
.getMetricsFeatureProvider();
mLifecycle.addObserver(new VisibilityLoggerMixin(getMetricsCategory(),
mMetricsFeatureProvider));
mLifecycle.onAttach(context);
}
}

View File

@@ -1,84 +0,0 @@
/*
* Copyright (C) 2016 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.core.instrumentation;
import android.content.Context;
import android.util.Pair;
/**
* Generic log writer interface.
*/
public interface LogWriter {
/**
* Logs a visibility event when view becomes visible.
*/
void visible(Context context, int source, int category);
/**
* Logs a visibility event when view becomes hidden.
*/
void hidden(Context context, int category);
/**
* Logs a user action.
*/
void action(int category, int value, Pair<Integer, Object>... taggedData);
/**
* Logs a user action.
*/
void action(int category, boolean value, Pair<Integer, Object>... taggedData);
/**
* Logs an user action.
*/
void action(Context context, int category, Pair<Integer, Object>... taggedData);
/**
* Logs an user action.
*/
void actionWithSource(Context context, int source, int category);
/**
* Logs an user action.
* @deprecated use {@link #action(int, int, Pair[])}
*/
@Deprecated
void action(Context context, int category, int value);
/**
* Logs an user action.
* @deprecated use {@link #action(int, boolean, Pair[])}
*/
@Deprecated
void action(Context context, int category, boolean value);
/**
* Logs an user action.
*/
void action(Context context, int category, String pkg, Pair<Integer, Object>... taggedData);
/**
* Logs a count.
*/
void count(Context context, String name, int value);
/**
* Logs a histogram event.
*/
void histogram(Context context, String name, int bucket);
}

View File

@@ -1,159 +0,0 @@
/*
* Copyright (C) 2016 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.core.instrumentation;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.util.Pair;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.util.ArrayList;
import java.util.List;
/**
* FeatureProvider for metrics.
*/
public class MetricsFeatureProvider {
private List<LogWriter> mLoggerWriters;
public MetricsFeatureProvider() {
mLoggerWriters = new ArrayList<>();
installLogWriters();
}
protected void installLogWriters() {
mLoggerWriters.add(new EventLogWriter());
}
public void visible(Context context, int source, int category) {
for (LogWriter writer : mLoggerWriters) {
writer.visible(context, source, category);
}
}
public void hidden(Context context, int category) {
for (LogWriter writer : mLoggerWriters) {
writer.hidden(context, category);
}
}
public void actionWithSource(Context context, int source, int category) {
for (LogWriter writer : mLoggerWriters) {
writer.actionWithSource(context, source, category);
}
}
/**
* Logs a user action. Includes the elapsed time since the containing
* fragment has been visible.
*/
public void action(VisibilityLoggerMixin visibilityLogger, int category, int value) {
for (LogWriter writer : mLoggerWriters) {
writer.action(category, value,
sinceVisibleTaggedData(visibilityLogger.elapsedTimeSinceVisible()));
}
}
/**
* Logs a user action. Includes the elapsed time since the containing
* fragment has been visible.
*/
public void action(VisibilityLoggerMixin visibilityLogger, int category, boolean value) {
for (LogWriter writer : mLoggerWriters) {
writer.action(category, value,
sinceVisibleTaggedData(visibilityLogger.elapsedTimeSinceVisible()));
}
}
public void action(Context context, int category, Pair<Integer, Object>... taggedData) {
for (LogWriter writer : mLoggerWriters) {
writer.action(context, category, taggedData);
}
}
/** @deprecated use {@link #action(VisibilityLoggerMixin, int, int)} */
@Deprecated
public void action(Context context, int category, int value) {
for (LogWriter writer : mLoggerWriters) {
writer.action(context, category, value);
}
}
/** @deprecated use {@link #action(VisibilityLoggerMixin, int, boolean)} */
@Deprecated
public void action(Context context, int category, boolean value) {
for (LogWriter writer : mLoggerWriters) {
writer.action(context, category, value);
}
}
public void action(Context context, int category, String pkg,
Pair<Integer, Object>... taggedData) {
for (LogWriter writer : mLoggerWriters) {
writer.action(context, category, pkg, taggedData);
}
}
public void count(Context context, String name, int value) {
for (LogWriter writer : mLoggerWriters) {
writer.count(context, name, value);
}
}
public void histogram(Context context, String name, int bucket) {
for (LogWriter writer : mLoggerWriters) {
writer.histogram(context, name, bucket);
}
}
public int getMetricsCategory(Object object) {
if (object == null || !(object instanceof Instrumentable)) {
return MetricsEvent.VIEW_UNKNOWN;
}
return ((Instrumentable) object).getMetricsCategory();
}
public void logDashboardStartIntent(Context context, Intent intent,
int sourceMetricsCategory) {
if (intent == null) {
return;
}
final ComponentName cn = intent.getComponent();
if (cn == null) {
final String action = intent.getAction();
if (TextUtils.isEmpty(action)) {
// Not loggable
return;
}
action(context, MetricsEvent.ACTION_SETTINGS_TILE_CLICK, action,
Pair.create(MetricsEvent.FIELD_CONTEXT, sourceMetricsCategory));
return;
} else if (TextUtils.equals(cn.getPackageName(), context.getPackageName())) {
// Going to a Setting internal page, skip click logging in favor of page's own
// visibility logging.
return;
}
action(context, MetricsEvent.ACTION_SETTINGS_TILE_CLICK, cn.flattenToString(),
Pair.create(MetricsEvent.FIELD_CONTEXT, sourceMetricsCategory));
}
private Pair<Integer, Object> sinceVisibleTaggedData(long timestamp) {
return Pair.create(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, timestamp);
}
}

View File

@@ -1,259 +0,0 @@
/*
* Copyright (C) 2016 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.core.instrumentation;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.overlay.FeatureFactory;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
public class SharedPreferencesLogger implements SharedPreferences {
private static final String LOG_TAG = "SharedPreferencesLogger";
private final String mTag;
private final Context mContext;
private final MetricsFeatureProvider mMetricsFeature;
private final Set<String> mPreferenceKeySet;
public SharedPreferencesLogger(Context context, String tag) {
mContext = context;
mTag = tag;
mMetricsFeature = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
mPreferenceKeySet = new ConcurrentSkipListSet<>();
}
@Override
public Map<String, ?> getAll() {
return null;
}
@Override
public String getString(String key, @Nullable String defValue) {
return defValue;
}
@Override
public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
return defValues;
}
@Override
public int getInt(String key, int defValue) {
return defValue;
}
@Override
public long getLong(String key, long defValue) {
return defValue;
}
@Override
public float getFloat(String key, float defValue) {
return defValue;
}
@Override
public boolean getBoolean(String key, boolean defValue) {
return defValue;
}
@Override
public boolean contains(String key) {
return false;
}
@Override
public Editor edit() {
return new EditorLogger();
}
@Override
public void registerOnSharedPreferenceChangeListener(
OnSharedPreferenceChangeListener listener) {
}
@Override
public void unregisterOnSharedPreferenceChangeListener(
OnSharedPreferenceChangeListener listener) {
}
private void logValue(String key, Object value) {
logValue(key, value, false /* forceLog */);
}
private void logValue(String key, Object value, boolean forceLog) {
final String prefKey = buildPrefKey(mTag, key);
if (!forceLog && !mPreferenceKeySet.contains(prefKey)) {
// Pref key doesn't exist in set, this is initial display so we skip metrics but
// keeps track of this key.
mPreferenceKeySet.add(prefKey);
return;
}
// TODO: Remove count logging to save some resource.
mMetricsFeature.count(mContext, buildCountName(prefKey, value), 1);
final Pair<Integer, Object> valueData;
if (value instanceof Long) {
final Long longVal = (Long) value;
final int intVal;
if (longVal > Integer.MAX_VALUE) {
intVal = Integer.MAX_VALUE;
} else if (longVal < Integer.MIN_VALUE) {
intVal = Integer.MIN_VALUE;
} else {
intVal = longVal.intValue();
}
valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE,
intVal);
} else if (value instanceof Integer) {
valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE,
value);
} else if (value instanceof Boolean) {
valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE,
(Boolean) value ? 1 : 0);
} else if (value instanceof Float) {
valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE,
value);
} else if (value instanceof String) {
Log.d(LOG_TAG, "Tried to log string preference " + prefKey + " = " + value);
valueData = null;
} else {
Log.w(LOG_TAG, "Tried to log unloggable object" + value);
valueData = null;
}
if (valueData != null) {
// Pref key exists in set, log it's change in metrics.
mMetricsFeature.action(mContext, MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE,
Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, prefKey),
valueData);
}
}
@VisibleForTesting
void logPackageName(String key, String value) {
final String prefKey = mTag + "/" + key;
mMetricsFeature.action(mContext, MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE, value,
Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, prefKey));
}
private void safeLogValue(String key, String value) {
new AsyncPackageCheck().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, key, value);
}
public static String buildCountName(String prefKey, Object value) {
return prefKey + "|" + value;
}
public static String buildPrefKey(String tag, String key) {
return tag + "/" + key;
}
private class AsyncPackageCheck extends AsyncTask<String, Void, Void> {
@Override
protected Void doInBackground(String... params) {
String key = params[0];
String value = params[1];
PackageManager pm = mContext.getPackageManager();
try {
// Check if this might be a component.
ComponentName name = ComponentName.unflattenFromString(value);
if (value != null) {
value = name.getPackageName();
}
} catch (Exception e) {
}
try {
pm.getPackageInfo(value, PackageManager.MATCH_ANY_USER);
logPackageName(key, value);
} catch (PackageManager.NameNotFoundException e) {
// Clearly not a package, and it's unlikely this preference is in prefSet, so
// lets force log it.
logValue(key, value, true /* forceLog */);
}
return null;
}
}
public class EditorLogger implements Editor {
@Override
public Editor putString(String key, @Nullable String value) {
safeLogValue(key, value);
return this;
}
@Override
public Editor putStringSet(String key, @Nullable Set<String> values) {
safeLogValue(key, TextUtils.join(",", values));
return this;
}
@Override
public Editor putInt(String key, int value) {
logValue(key, value);
return this;
}
@Override
public Editor putLong(String key, long value) {
logValue(key, value);
return this;
}
@Override
public Editor putFloat(String key, float value) {
logValue(key, value);
return this;
}
@Override
public Editor putBoolean(String key, boolean value) {
logValue(key, value);
return this;
}
@Override
public Editor remove(String key) {
return this;
}
@Override
public Editor clear() {
return this;
}
@Override
public boolean commit() {
return true;
}
@Override
public void apply() {
}
}
}

View File

@@ -1,100 +0,0 @@
/*
* Copyright (C) 2016 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.core.instrumentation;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.SettingsActivity;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnAttach;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
import static com.android.settings.core.instrumentation.Instrumentable.METRICS_CATEGORY_UNKNOWN;
/**
* Logs visibility change of a fragment.
*/
public class VisibilityLoggerMixin implements LifecycleObserver, OnResume, OnPause, OnAttach {
private static final String TAG = "VisibilityLoggerMixin";
private final int mMetricsCategory;
private MetricsFeatureProvider mMetricsFeature;
private int mSourceMetricsCategory = MetricsProto.MetricsEvent.VIEW_UNKNOWN;
private long mVisibleTimestamp;
public VisibilityLoggerMixin(int metricsCategory) {
// MetricsFeature will be set during onAttach.
this(metricsCategory, null /* metricsFeature */);
}
public VisibilityLoggerMixin(int metricsCategory, MetricsFeatureProvider metricsFeature) {
mMetricsCategory = metricsCategory;
mMetricsFeature = metricsFeature;
}
@Override
public void onAttach(Context context) {
mMetricsFeature = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
}
@Override
public void onResume() {
mVisibleTimestamp = SystemClock.elapsedRealtime();
if (mMetricsFeature != null && mMetricsCategory != METRICS_CATEGORY_UNKNOWN) {
mMetricsFeature.visible(null /* context */, mSourceMetricsCategory, mMetricsCategory);
}
}
@Override
public void onPause() {
mVisibleTimestamp = 0;
if (mMetricsFeature != null && mMetricsCategory != METRICS_CATEGORY_UNKNOWN) {
mMetricsFeature.hidden(null /* context */, mMetricsCategory);
}
}
/**
* Sets source metrics category for this logger. Source is the caller that opened this UI.
*/
public void setSourceMetricsCategory(Activity activity) {
if (mSourceMetricsCategory != MetricsProto.MetricsEvent.VIEW_UNKNOWN || activity == null) {
return;
}
final Intent intent = activity.getIntent();
if (intent == null) {
return;
}
mSourceMetricsCategory = intent.getIntExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY,
MetricsProto.MetricsEvent.VIEW_UNKNOWN);
}
/** Returns elapsed time since onResume() */
public long elapsedTimeSinceVisible() {
if (mVisibleTimestamp == 0) {
return 0;
}
return SystemClock.elapsedRealtime() - mVisibleTimestamp;
}
}

View File

@@ -41,7 +41,6 @@ import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.R.id;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardData.SuggestionConditionHeaderData;
import com.android.settings.dashboard.conditional.Condition;
import com.android.settings.dashboard.conditional.ConditionAdapter;
@@ -50,6 +49,7 @@ import com.android.settings.dashboard.suggestions.SuggestionControllerMixin;
import com.android.settings.dashboard.suggestions.SuggestionDismissController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.Utils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.Tile;

View File

@@ -39,13 +39,13 @@ import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.R.id;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardDataV2.ConditionHeaderData;
import com.android.settings.dashboard.conditional.Condition;
import com.android.settings.dashboard.conditional.ConditionAdapterV2;
import com.android.settings.dashboard.suggestions.SuggestionAdapterV2;
import com.android.settings.dashboard.suggestions.SuggestionControllerMixin;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
@@ -305,7 +305,8 @@ public class DashboardAdapterV2 extends RecyclerView.Adapter<DashboardAdapterV2.
void onBindSuggestion(final SuggestionContainerHolder holder, int position) {
// If there is suggestions to show, it will be at position 0 as we don't show the suggestion
// header anymore.
final List<Suggestion> suggestions = mDashboardData.getSuggestions();
final List<Suggestion> suggestions =
(List<Suggestion>) mDashboardData.getItemEntityByPosition(position);
final int suggestionCount = suggestions.size();
if (suggestions != null && suggestionCount > 0) {
holder.summary.setText(""+suggestionCount);

View File

@@ -41,8 +41,9 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.core.FeatureFlags;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.drawer.CategoryManager;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.ProfileSelectDialog;
@@ -159,7 +160,8 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
pref.setFragment(clsName);
} else if (tile.intent != null) {
final Intent intent = new Intent(tile.intent);
intent.putExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY, sourceMetricsCategory);
intent.putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY,
sourceMetricsCategory);
if (action != null) {
intent.setAction(action);
}
@@ -208,7 +210,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
return;
}
final Intent intent = new Intent(tile.intent)
.putExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY,
.putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY,
MetricsEvent.DASHBOARD_SUMMARY)
.putExtra(SettingsDrawerActivity.EXTRA_SHOW_MENU, true)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);

View File

@@ -1,205 +0,0 @@
/*
* Copyright (C) 2017 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.dashboard;
import static android.provider.SearchIndexablesContract.SITE_MAP_COLUMNS;
import static com.android.settings.dashboard.DashboardFragmentRegistry.CATEGORY_KEY_TO_PARENT_MAP;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.provider.SearchIndexablesContract.SiteMapColumns;
import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.support.v4.util.ArrayMap;
import android.text.TextUtils;
import android.util.Log;
import com.android.settings.SettingsActivity;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.IndexDatabaseHelper;
import com.android.settings.search.IndexDatabaseHelper.IndexColumns;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.Tile;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* A manager class that maintains a "site map" and look up breadcrumb for a certain page on demand.
* <p/>
* The methods on this class can only be called on a background thread.
*/
public class SiteMapManager {
private static final String TAG = "SiteMapManager";
private static final boolean DEBUG_TIMING = false;
private static final String[] CLASS_TO_SCREEN_TITLE_COLUMNS = {
IndexColumns.CLASS_NAME,
IndexColumns.SCREEN_TITLE,
};
private final List<SiteMapPair> mPairs = new ArrayList<>();
private boolean mInitialized;
/**
* Given a fragment class name and its screen title, build a breadcrumb from Settings root to
* this screen.
* <p/>
* Not all screens have a full breadcrumb path leading up to root, it's because either some
* page in the breadcrumb path is not indexed, or it's only reachable via search.
*/
@WorkerThread
public synchronized List<String> buildBreadCrumb(Context context, String clazz,
String screenTitle) {
init(context);
final long startTime = System.currentTimeMillis();
final List<String> breadcrumbs = new ArrayList<>();
if (!mInitialized) {
Log.w(TAG, "SiteMap is not initialized yet, skipping");
return breadcrumbs;
}
breadcrumbs.add(screenTitle);
String currentClass = clazz;
String currentTitle = screenTitle;
// Look up current page's parent, if found add it to breadcrumb string list, and repeat.
while (true) {
final SiteMapPair pair = lookUpParent(currentClass, currentTitle);
if (pair == null) {
if (DEBUG_TIMING) {
Log.d(TAG, "BreadCrumb timing: " + (System.currentTimeMillis() - startTime));
}
return breadcrumbs;
}
breadcrumbs.add(0, pair.parentTitle);
currentClass = pair.parentClass;
currentTitle = pair.parentTitle;
}
}
/**
* Initialize a list of {@link SiteMapPair}s. Each pair knows about a single parent-child
* page relationship.
*
* We get the knowledge of such mPairs from 2 sources:
* 1. Static indexing time: we know which page(s) a parent can open by parsing its pref xml.
* 2. IA: We know from {@link DashboardFeatureProvider} which page can be dynamically
* injected to where.
*/
@VisibleForTesting
@WorkerThread
synchronized void init(Context context) {
if (mInitialized) {
// Make sure only init once.
return;
}
final long startTime = System.currentTimeMillis();
// First load site map from static index table.
final Context appContext = context.getApplicationContext();
final SQLiteDatabase db = IndexDatabaseHelper.getInstance(appContext).getReadableDatabase();
Cursor sitemap = db.query(IndexDatabaseHelper.Tables.TABLE_SITE_MAP, SITE_MAP_COLUMNS, null,
null, null, null, null);
while (sitemap.moveToNext()) {
final SiteMapPair pair = new SiteMapPair(
sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.PARENT_CLASS)),
sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.PARENT_TITLE)),
sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.CHILD_CLASS)),
sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.CHILD_TITLE)));
mPairs.add(pair);
}
sitemap.close();
// Then prepare a local map that contains class name -> screen title mapping. This is needed
// to figure out the display name for any fragment if it's injected dynamically through IA.
final Map<String, String> classToTitleMap = new ArrayMap<>();
final Cursor titleQuery = db.query(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX,
CLASS_TO_SCREEN_TITLE_COLUMNS, null, null, null, null, null);
while (titleQuery.moveToNext()) {
classToTitleMap.put(
titleQuery.getString(titleQuery.getColumnIndex(IndexColumns.CLASS_NAME)),
titleQuery.getString(titleQuery.getColumnIndex(IndexColumns.SCREEN_TITLE)));
}
titleQuery.close();
// Loop through all IA categories and pages and build additional SiteMapPairs
List<DashboardCategory> categories = FeatureFactory.getFactory(context)
.getDashboardFeatureProvider(context).getAllCategories();
for (DashboardCategory category : categories) {
// Find the category key first.
final String parentClass = CATEGORY_KEY_TO_PARENT_MAP.get(category.key);
if (parentClass == null) {
continue;
}
// Use the key to look up parent (which page hosts this key)
final String parentName = classToTitleMap.get(parentClass);
if (parentName == null) {
continue;
}
// Build parent-child mPairs for all children listed under this key.
for (Tile tile : category.getTiles()) {
final String childTitle = tile.title.toString();
String childClass = null;
if (tile.metaData != null) {
childClass = tile.metaData.getString(
SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS);
}
if (childClass == null) {
continue;
}
mPairs.add(new SiteMapPair(parentClass, parentName, childClass, childTitle));
}
}
// Done.
mInitialized = true;
if (DEBUG_TIMING) {
Log.d(TAG, "Init timing: " + (System.currentTimeMillis() - startTime));
}
}
@WorkerThread
private SiteMapPair lookUpParent(String clazz, String title) {
for (SiteMapPair pair : mPairs) {
if (TextUtils.equals(pair.childClass, clazz)
&& TextUtils.equals(title, pair.childTitle)) {
return pair;
}
}
return null;
}
/**
* Data model for a parent-child page pair.
*/
private static class SiteMapPair {
public final String parentClass;
public final String parentTitle;
public final String childClass;
public final String childTitle;
public SiteMapPair(String parentClass, String parentTitle, String childClass,
String childTitle) {
this.parentClass = parentClass;
this.parentTitle = parentTitle;
this.childClass = childClass;
this.childTitle = childTitle;
}
}
}

View File

@@ -24,8 +24,8 @@ import android.os.PersistableBundle;
import android.support.annotation.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
public abstract class Condition {

View File

@@ -27,13 +27,13 @@ import android.widget.Button;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardAdapter;
import com.android.settings.dashboard.DashboardAdapter.DashboardItemHolder;
import com.android.settings.dashboard.DashboardData;
import com.android.settings.dashboard.DashboardData.HeaderMode;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.WirelessUtils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import java.util.List;
import java.util.Objects;

View File

@@ -27,10 +27,10 @@ import android.widget.Button;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardAdapterV2.DashboardItemHolder;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.WirelessUtils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import java.util.List;
import java.util.Objects;

View File

@@ -27,10 +27,10 @@ import android.view.ViewGroup;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardAdapter.DashboardItemHolder;
import com.android.settings.dashboard.DashboardAdapter.IconCache;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import java.util.List;
import java.util.Objects;

View File

@@ -31,10 +31,10 @@ import android.widget.LinearLayout;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardAdapterV2.DashboardItemHolder;
import com.android.settings.dashboard.DashboardAdapterV2.IconCache;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
@@ -56,10 +56,7 @@ public class SuggestionAdapterV2 extends RecyclerView.Adapter<DashboardItemHolde
private final ArrayList<String> mSuggestionsShownLogged;
private final SuggestionControllerMixin mSuggestionControllerMixin;
private final Callback mCallback;
private final int mMultipleCardsMarginEnd;
private final int mWidthSingleCard;
private final int mWidthTwoCards;
private final int mWidthMultipleCards;
private final CardConfig mConfig;
private List<Suggestion> mSuggestions;
@@ -89,13 +86,7 @@ public class SuggestionAdapterV2 extends RecyclerView.Adapter<DashboardItemHolde
if (lifecycle != null) {
lifecycle.addObserver(this);
}
final Resources res = mContext.getResources();
mMultipleCardsMarginEnd = res.getDimensionPixelOffset(R.dimen.suggestion_card_margin_end);
mWidthSingleCard = res.getDimensionPixelOffset(R.dimen.suggestion_card_width_one_card);
mWidthTwoCards = res.getDimensionPixelOffset(R.dimen.suggestion_card_width_two_cards);
mWidthMultipleCards =
res.getDimensionPixelOffset(R.dimen.suggestion_card_width_multiple_cards);
mConfig = CardConfig.get(context);
setHasStableIds(true);
}
@@ -116,7 +107,7 @@ public class SuggestionAdapterV2 extends RecyclerView.Adapter<DashboardItemHolde
mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, id);
mSuggestionsShownLogged.add(id);
}
setCardWidthAndMargin(holder, suggestionCount);
mConfig.setCardLayout(holder, suggestionCount, position);
holder.icon.setImageDrawable(mCache.getIcon(suggestion.getIcon()));
holder.title.setText(suggestion.getTitle());
holder.title.setSingleLine(suggestionCount == 1);
@@ -220,12 +211,61 @@ public class SuggestionAdapterV2 extends RecyclerView.Adapter<DashboardItemHolde
return mSuggestions;
}
private void setCardWidthAndMargin(DashboardItemHolder holder, int suggestionCount) {
final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
suggestionCount == 1
? mWidthSingleCard : suggestionCount == 2 ? mWidthTwoCards : mWidthMultipleCards,
LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMarginEnd(suggestionCount == 1 ? 0 : mMultipleCardsMarginEnd);
holder.itemView.setLayoutParams(params);
private static class CardConfig {
// Card start/end margin
private final int mMarginInner;
private final int mMarginOuter;
// Card width for different numbers of cards
private final int mWidthSingleCard;
private final int mWidthTwoCards;
private final int mWidthMultipleCards;
// padding between icon and title
private final int mPaddingTitleTopSingleCard;
private final int mPaddingTitleTopMultipleCards;
private static CardConfig sConfig;
private CardConfig(Context context) {
final Resources res = context.getResources();
mMarginInner =
res.getDimensionPixelOffset(R.dimen.suggestion_card_inner_margin);
mMarginOuter =
res.getDimensionPixelOffset(R.dimen.suggestion_card_outer_margin);
mWidthSingleCard = res.getDimensionPixelOffset(R.dimen.suggestion_card_width_one_card);
mWidthTwoCards = res.getDimensionPixelOffset(R.dimen.suggestion_card_width_two_cards);
mWidthMultipleCards =
res.getDimensionPixelOffset(R.dimen.suggestion_card_width_multiple_cards);
mPaddingTitleTopSingleCard =
res.getDimensionPixelOffset(R.dimen.suggestion_card_title_padding_bottom_one_card);
mPaddingTitleTopMultipleCards = res.getDimensionPixelOffset(
R.dimen.suggestion_card_title_padding_bottom_multiple_cards);
}
public static CardConfig get(Context context) {
if (sConfig == null) {
sConfig = new CardConfig(context);
}
return sConfig;
}
private void setCardLayout(DashboardItemHolder holder, int suggestionCount,
int position) {
final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
suggestionCount == 1
? mWidthSingleCard : suggestionCount == 2
? mWidthTwoCards : mWidthMultipleCards,
LinearLayout.LayoutParams.WRAP_CONTENT);
if (suggestionCount == 1) {
params.setMarginStart(mMarginOuter);
params.setMarginEnd(mMarginOuter);
} else {
params.setMarginStart(
position == 0 ? mMarginOuter : mMarginInner);
params.setMarginEnd(position == suggestionCount - 1 ? mMarginOuter : 0);
}
holder.itemView.setLayoutParams(params);
}
}
}

View File

@@ -36,7 +36,6 @@ import com.android.settings.Settings.DoubleTapPowerSuggestionActivity;
import com.android.settings.Settings.DoubleTwistSuggestionActivity;
import com.android.settings.Settings.NightDisplaySuggestionActivity;
import com.android.settings.Settings.SwipeToNotificationSuggestionActivity;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.fingerprint.FingerprintEnrollSuggestionActivity;
import com.android.settings.fingerprint.FingerprintSuggestionActivity;
import com.android.settings.gestures.DoubleTapPowerPreferenceController;
@@ -49,6 +48,7 @@ import com.android.settings.password.ScreenLockSuggestionActivity;
import com.android.settings.support.NewDeviceIntroSuggestionActivity;
import com.android.settings.wallpaper.WallpaperSuggestionActivity;
import com.android.settings.wifi.WifiCallingSuggestionActivity;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.drawer.Tile;
import java.util.List;

View File

@@ -25,8 +25,8 @@ import android.os.RemoteException;
import android.util.SparseIntArray;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.utils.ThreadUtils;
import java.util.ArrayList;
@@ -204,6 +204,10 @@ public class DataSaverBackend {
public void onRestrictBackgroundChanged(final boolean isDataSaving) throws RemoteException {
ThreadUtils.postOnMainThread(() -> handleRestrictBackgroundChanged(isDataSaving));
}
@Override
public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) {
}
};
public interface Listener {

View File

@@ -35,8 +35,9 @@ import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.instrumentation.Instrumentable;
import com.android.settings.core.instrumentation.VisibilityLoggerMixin;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.datetime.ZoneGetter;
import java.text.Collator;
@@ -57,8 +58,7 @@ public class ZonePicker extends ListFragment implements Instrumentable {
private static final int MENU_TIMEZONE = Menu.FIRST+1;
private static final int MENU_ALPHABETICAL = Menu.FIRST;
private final VisibilityLoggerMixin mVisibilityLoggerMixin =
new VisibilityLoggerMixin(getMetricsCategory());
private VisibilityLoggerMixin mVisibilityLoggerMixin;
private boolean mSortedByTimezone;
@@ -144,12 +144,6 @@ public class ZonePicker extends ListFragment implements Instrumentable {
return -1;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mVisibilityLoggerMixin.onAttach(context);
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.ZONE_PICKER;
@@ -169,6 +163,13 @@ public class ZonePicker extends ListFragment implements Instrumentable {
activity.setTitle(R.string.date_time_set_timezone);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(),
FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider());
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {

View File

@@ -23,10 +23,10 @@ import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.widget.Switch;
import com.android.internal.util.Preconditions;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.widget.SwitchBar;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.Preconditions;
import com.android.settings.widget.SwitchBar;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
/** Handles the logic for flipping the storage management toggle on a {@link SwitchBar}. */
public class AutomaticStorageManagerSwitchBarController

View File

@@ -398,8 +398,6 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new CameraLaserSensorPreferenceController(context));
controllers.add(new WifiDisplayCertificationPreferenceController(context));
controllers.add(new WifiVerboseLoggingPreferenceController(context));
controllers.add(new WifiAggressiveHandoverPreferenceController(context));
controllers.add(new WifiRoamScansPreferenceController(context));
controllers.add(new MobileDataAlwaysOnPreferenceController(context));
controllers.add(new TetheringHardwareAccelPreferenceController(context));
controllers.add(new SelectUsbConfigPreferenceController(context, lifecycle));
@@ -424,6 +422,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new ShowLayoutBoundsPreferenceController(context));
controllers.add(new RtlLayoutPreferenceController(context));
controllers.add(new WindowAnimationScalePreferenceController(context));
controllers.add(new EmulateDisplayCutoutPreferenceController(context));
controllers.add(new TransitionAnimationScalePreferenceController(context));
controllers.add(new AnimatorDurationScalePreferenceController(context));
controllers.add(new SecondaryDisplayPreferenceController(context));
@@ -441,6 +440,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new ProfileGpuRenderingPreferenceController(context));
controllers.add(new KeepActivitiesPreferenceController(context));
controllers.add(new BackgroundProcessLimitPreferenceController(context));
controllers.add(new ShowFirstCrashDialogPreferenceController(context));
controllers.add(new AppsNotRespondingPreferenceController(context));
controllers.add(new NotificationChannelWarningsPreferenceController(context));
controllers.add(new AllowAppsOnExternalPreferenceController(context));

View File

@@ -0,0 +1,122 @@
/*
* 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.development;
import android.content.Context;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.TwoStatePreference;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
public class EmulateDisplayCutoutPreferenceController extends
DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener,
PreferenceControllerMixin {
private static final String EMULATION_OVERLAY = "com.android.internal.display.cutout.emulation";
private static final String KEY = "display_cutout_emulation";
private final IOverlayManager mOverlayManager;
private final boolean mAvailable;
private TwoStatePreference mPreference;
@VisibleForTesting
EmulateDisplayCutoutPreferenceController(Context context, IOverlayManager overlayManager) {
super(context);
mOverlayManager = overlayManager;
mAvailable = overlayManager != null && getEmulationOverlayInfo() != null;
}
public EmulateDisplayCutoutPreferenceController(Context context) {
this(context, IOverlayManager.Stub.asInterface(
ServiceManager.getService(Context.OVERLAY_SERVICE)));
}
@Override
public boolean isAvailable() {
return mAvailable;
}
@Override
public String getPreferenceKey() {
return KEY;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
setPreference((TwoStatePreference) screen.findPreference(getPreferenceKey()));
}
@VisibleForTesting
void setPreference(TwoStatePreference preference) {
mPreference = preference;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
return writeEnabled((boolean) newValue);
}
private boolean writeEnabled(boolean newValue) {
OverlayInfo current = getEmulationOverlayInfo();
if (current == null || current.isEnabled() == newValue) {
return false;
}
try {
return mOverlayManager.setEnabled(EMULATION_OVERLAY, newValue, UserHandle.USER_SYSTEM);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Override
public void updateState(Preference preference) {
OverlayInfo overlayInfo = getEmulationOverlayInfo();
mPreference.setChecked(overlayInfo != null && overlayInfo.isEnabled());
}
private OverlayInfo getEmulationOverlayInfo() {
OverlayInfo overlayInfo = null;
try {
overlayInfo = mOverlayManager.getOverlayInfo(EMULATION_OVERLAY, UserHandle.USER_SYSTEM);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
return overlayInfo;
}
@Override
protected void onDeveloperOptionsSwitchEnabled() {
mPreference.setEnabled(true);
}
@Override
protected void onDeveloperOptionsSwitchDisabled() {
writeEnabled(false);
mPreference.setChecked(false);
mPreference.setEnabled(false);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 The Android Open Source Project
* 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.
@@ -17,7 +17,7 @@
package com.android.settings.development;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
@@ -26,29 +26,34 @@ import android.support.v7.preference.PreferenceScreen;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
public class WifiRoamScansPreferenceController extends
public class ShowFirstCrashDialogPreferenceController extends
DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener,
PreferenceControllerMixin {
private static final String WIFI_ALLOW_SCAN_WITH_TRAFFIC_KEY = "wifi_allow_scan_with_traffic";
private static final String SHOW_FIRST_CRASH_DIALOG_KEY = "show_first_crash_dialog";
@VisibleForTesting
static final int SETTING_VALUE_ON = 1;
@VisibleForTesting
static final int SETTING_VALUE_OFF = 0;
private final WifiManager mWifiManager;
private SwitchPreference mPreference;
public WifiRoamScansPreferenceController(Context context) {
public ShowFirstCrashDialogPreferenceController(Context context) {
super(context);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
}
@Override
public String getPreferenceKey() {
return WIFI_ALLOW_SCAN_WITH_TRAFFIC_KEY;
return SHOW_FIRST_CRASH_DIALOG_KEY;
}
@Override
public boolean isAvailable() {
// If the global setting is on, hide this preference since the global overrides
// any user preference.
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.SHOW_FIRST_CRASH_DIALOG, SETTING_VALUE_OFF) == SETTING_VALUE_OFF;
}
@Override
@@ -61,14 +66,17 @@ public class WifiRoamScansPreferenceController extends
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean isEnabled = (Boolean) newValue;
mWifiManager.setAllowScansWithTraffic(isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
return true;
}
@Override
public void updateState(Preference preference) {
final boolean enabled = mWifiManager.getAllowScansWithTraffic() > 0;
mPreference.setChecked(enabled);
final int mode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION, SETTING_VALUE_OFF);
mPreference.setChecked(mode != SETTING_VALUE_OFF);
}
@Override
@@ -78,7 +86,8 @@ public class WifiRoamScansPreferenceController extends
@Override
protected void onDeveloperOptionsSwitchDisabled() {
mWifiManager.setAllowScansWithTraffic(SETTING_VALUE_OFF);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION, SETTING_VALUE_OFF);
mPreference.setEnabled(false);
mPreference.setChecked(false);
}

View File

@@ -1,85 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.development;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.support.annotation.VisibleForTesting;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
public class WifiAggressiveHandoverPreferenceController extends
DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener,
PreferenceControllerMixin {
private static final String WIFI_AGGRESSIVE_HANDOVER_KEY = "wifi_aggressive_handover";
@VisibleForTesting
static final int SETTING_VALUE_ON = 1;
@VisibleForTesting
static final int SETTING_VALUE_OFF = 0;
private final WifiManager mWifiManager;
private SwitchPreference mPreference;
public WifiAggressiveHandoverPreferenceController(Context context) {
super(context);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
}
@Override
public String getPreferenceKey() {
return WIFI_AGGRESSIVE_HANDOVER_KEY;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = (SwitchPreference) screen.findPreference(getPreferenceKey());
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean isEnabled = (Boolean) newValue;
mWifiManager.enableAggressiveHandover(isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
return true;
}
@Override
public void updateState(Preference preference) {
boolean enabled = mWifiManager.getAggressiveHandover() > 0;
mPreference.setChecked(enabled);
}
@Override
protected void onDeveloperOptionsSwitchEnabled() {
mPreference.setEnabled(true);
}
@Override
protected void onDeveloperOptionsSwitchDisabled() {
mWifiManager.enableAggressiveHandover(SETTING_VALUE_OFF);
mPreference.setChecked(false);
mPreference.setEnabled(false);
}
}

View File

@@ -16,6 +16,7 @@
package com.android.settings.development.qstile;
import android.content.Context;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
@@ -30,6 +31,7 @@ import android.view.IWindowManager;
import android.view.ThreadedRenderer;
import android.view.View;
import android.view.WindowManagerGlobal;
import android.widget.Toast;
import com.android.internal.app.LocalePicker;
import com.android.settings.wrapper.IWindowManagerWrapper;
@@ -145,12 +147,17 @@ public abstract class DevelopmentTiles extends TileService {
public static class WindowTrace extends DevelopmentTiles {
@VisibleForTesting
IWindowManagerWrapper mWindowManager;
@VisibleForTesting
Toast mToast;
@Override
public void onCreate() {
super.onCreate();
mWindowManager = new IWindowManagerWrapper(WindowManagerGlobal
.getWindowManagerService());
Context context = getApplicationContext();
CharSequence text = "Trace written to /data/misc/wmtrace/wm_trace.pb";
mToast = Toast.makeText(context, text, Toast.LENGTH_LONG);
}
@Override
@@ -171,6 +178,7 @@ public abstract class DevelopmentTiles extends TileService {
mWindowManager.startWindowTrace();
} else {
mWindowManager.stopWindowTrace();
mToast.show();
}
} catch (RemoteException e) {
Log.e(TAG, "Could not set window trace status." + e.toString());
@@ -188,11 +196,16 @@ public abstract class DevelopmentTiles extends TileService {
static final int SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE = 1026;
@VisibleForTesting
IBinder mSurfaceFlinger;
@VisibleForTesting
Toast mToast;
@Override
public void onCreate() {
super.onCreate();
mSurfaceFlinger = ServiceManager.getService("SurfaceFlinger");
Context context = getApplicationContext();
CharSequence text = "Trace written to /data/misc/wmtrace/layers_trace.pb";
mToast = Toast.makeText(context, text, Toast.LENGTH_LONG);
}
@Override
@@ -230,6 +243,9 @@ public abstract class DevelopmentTiles extends TileService {
data.writeInt(isEnabled ? 1 : 0);
mSurfaceFlinger.transact(SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE,
data, null, 0 /* flags */);
if (!isEnabled){
mToast.show();
}
}
} catch (RemoteException e) {
Log.e(TAG, "Could not set layer tracing." + e.toString());

View File

@@ -34,11 +34,11 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnResume;

View File

@@ -25,12 +25,12 @@ import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.PreferenceScreen;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.deletionhelper.ActivationWarningFragment;
import com.android.settings.widget.MasterSwitchController;
import com.android.settings.widget.MasterSwitchPreference;
import com.android.settings.widget.SwitchWidgetController;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnResume;

View File

@@ -38,11 +38,11 @@ import com.android.settings.Settings;
import com.android.settings.Utils;
import com.android.settings.applications.manageapplications.ManageApplications;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.deviceinfo.PrivateVolumeSettings.SystemInfoFragment;
import com.android.settings.deviceinfo.StorageItemPreference;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.deviceinfo.StorageMeasurement;
import com.android.settingslib.deviceinfo.StorageVolumeProvider;

View File

@@ -27,11 +27,11 @@ import android.support.v7.preference.Preference;
import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.search.DatabaseIndexingUtils;
import com.android.settings.search.InlineSwitchPayload;
import com.android.settings.search.ResultPayload;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
public class AmbientDisplayNotificationsPreferenceController extends
AbstractPreferenceController implements PreferenceControllerMixin,

View File

@@ -23,13 +23,13 @@ import android.provider.SearchIndexableResource;
import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.gestures.DoubleTapScreenPreferenceController;
import com.android.settings.gestures.PickupGesturePreferenceController;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;

View File

@@ -20,9 +20,9 @@ import android.support.v7.preference.TwoStatePreference;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.view.RotationPolicy;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;

View File

@@ -29,9 +29,9 @@ import android.text.TextUtils;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import libcore.util.Objects;

View File

@@ -13,9 +13,11 @@
*/
package com.android.settings.display;
import android.app.admin.DevicePolicyManager;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
import android.content.Context;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.util.Log;
@@ -25,10 +27,9 @@ import com.android.settings.TimeoutListPreference;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.wrapper.DevicePolicyManagerWrapper;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.core.AbstractPreferenceController;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
public class TimeoutPreferenceController extends AbstractPreferenceController implements
PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
@@ -69,6 +70,13 @@ public class TimeoutPreferenceController extends AbstractPreferenceController im
timeoutListPreference.removeUnusableTimeouts(maxTimeout, admin);
}
updateTimeoutPreferenceDescription(timeoutListPreference, currentTimeout);
EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(
mContext, UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT,
UserHandle.myUserId());
if(admin != null) {
timeoutListPreference.removeUnusableTimeouts(0/* disable all*/, admin);
}
}
@Override

View File

@@ -45,7 +45,7 @@ public class ManageDeviceAdminPreferenceController extends AbstractPreferenceCon
@Override
public boolean isAvailable() {
return true;
return mContext.getResources().getBoolean(R.bool.config_show_manage_device_admin);
}
@Override

View File

@@ -48,7 +48,6 @@ import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.ActionButtonPreference;
import com.android.settings.wrapper.DevicePolicyManagerWrapper;
@@ -56,6 +55,7 @@ import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnDestroy;

View File

@@ -54,9 +54,10 @@ public class BackgroundActivityPreferenceController extends AbstractPreferenceCo
private final int mUid;
@VisibleForTesting
DevicePolicyManagerWrapper mDpm;
@VisibleForTesting
BatteryUtils mBatteryUtils;
private Fragment mFragment;
private String mTargetPackage;
private boolean mIsPreOApp;
private PowerWhitelistBackend mPowerWhitelistBackend;
public BackgroundActivityPreferenceController(Context context, Fragment fragment,
@@ -77,7 +78,7 @@ public class BackgroundActivityPreferenceController extends AbstractPreferenceCo
mUid = uid;
mFragment = fragment;
mTargetPackage = packageName;
mIsPreOApp = isLegacyApp(packageName);
mBatteryUtils = BatteryUtils.getInstance(context);
}
@Override
@@ -109,12 +110,7 @@ public class BackgroundActivityPreferenceController extends AbstractPreferenceCo
* activity for this package
*/
public void setUnchecked(Preference preference) {
if (mIsPreOApp) {
mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage,
AppOpsManager.MODE_IGNORED);
}
mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage,
AppOpsManager.MODE_IGNORED);
mBatteryUtils.setForceAppStandby(mUid, mTargetPackage, AppOpsManager.MODE_IGNORED);
((SwitchPreference) preference).setChecked(false);
updateSummary(preference);
}
@@ -133,30 +129,11 @@ public class BackgroundActivityPreferenceController extends AbstractPreferenceCo
dialogFragment.show(mFragment.getFragmentManager(), TAG);
return false;
}
if (mIsPreOApp) {
mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage,
AppOpsManager.MODE_ALLOWED);
}
mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage,
AppOpsManager.MODE_ALLOWED);
mBatteryUtils.setForceAppStandby(mUid, mTargetPackage, AppOpsManager.MODE_ALLOWED);
updateSummary(preference);
return true;
}
@VisibleForTesting
boolean isLegacyApp(final String packageName) {
try {
ApplicationInfo info = mPackageManager.getApplicationInfo(packageName,
PackageManager.GET_META_DATA);
return info.targetSdkVersion < Build.VERSION_CODES.O;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Cannot find package: " + packageName, e);
}
return false;
}
@VisibleForTesting
void updateSummary(Preference preference) {
if (mPowerWhitelistBackend.isWhitelisted(mTargetPackage)) {

View File

@@ -49,10 +49,10 @@ import com.android.settings.SettingsActivity;
import com.android.settings.core.FeatureFlags;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.Utils;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.fuelgauge.anomaly.Anomaly;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnDestroy;

View File

@@ -398,6 +398,19 @@ public class BatteryUtils {
return timeMs * 1000;
}
public void setForceAppStandby(int uid, String packageName,
int mode) {
final boolean isPreOApp = isLegacyApp(packageName);
if (isPreOApp) {
// Control whether app could run in the background if it is pre O app
mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName,
mode);
}
// Control whether app could run jobs in the background
mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName,
mode);
}
public void initBatteryStatsHelper(BatteryStatsHelper statsHelper, Bundle bundle,
UserManager userManager) {
statsHelper.create(bundle);
@@ -481,5 +494,18 @@ public class BatteryUtils {
return 0;
}
public boolean isLegacyApp(final String packageName) {
try {
ApplicationInfo info = mPackageManager.getApplicationInfo(packageName,
PackageManager.GET_META_DATA);
return info.targetSdkVersion < Build.VERSION_CODES.O;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Cannot find package: " + packageName, e);
}
return false;
}
}

View File

@@ -362,6 +362,16 @@ public class FakeUid extends Uid {
return null;
}
@Override
public long getCpuActiveTime() {
return 0;
}
@Override
public long[] getCpuClusterTimes() {
return null;
}
@Override
public long[] getCpuFreqTimes(int procState, int which) {
return null;

View File

@@ -47,7 +47,6 @@ import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.applications.manageapplications.ManageApplications;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.display.AmbientDisplayPreferenceController;
import com.android.settings.display.AutoBrightnessPreferenceController;
@@ -61,6 +60,7 @@ import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;

View File

@@ -54,7 +54,6 @@ import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.applications.manageapplications.ManageApplications;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.display.AmbientDisplayPreferenceController;
import com.android.settings.display.AutoBrightnessPreferenceController;
@@ -67,6 +66,7 @@ import com.android.settings.fuelgauge.anomaly.AnomalyLoader;
import com.android.settings.fuelgauge.anomaly.AnomalySummaryPreferenceController;
import com.android.settings.fuelgauge.anomaly.AnomalyUtils;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.ArrayList;

View File

@@ -20,9 +20,11 @@ package com.android.settings.fuelgauge;
import android.app.AppOpsManager;
import android.content.Context;
import android.support.annotation.VisibleForTesting;
import android.support.v14.preference.PreferenceFragment;
import android.support.v7.preference.Preference;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.core.BasePreferenceController;
@@ -37,12 +39,21 @@ public class RestrictAppPreferenceController extends BasePreferenceController {
private AppOpsManager mAppOpsManager;
private List<AppOpsManager.PackageOps> mPackageOps;
private SettingsActivity mSettingsActivity;
private PreferenceFragment mPreferenceFragment;
public RestrictAppPreferenceController(Context context) {
super(context, KEY_RESTRICT_APP);
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
}
public RestrictAppPreferenceController(SettingsActivity settingsActivity,
PreferenceFragment preferenceFragment) {
this(settingsActivity.getApplicationContext());
mSettingsActivity = settingsActivity;
mPreferenceFragment = preferenceFragment;
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
@@ -51,13 +62,27 @@ public class RestrictAppPreferenceController extends BasePreferenceController {
@Override
public void updateState(Preference preference) {
super.updateState(preference);
mPackageOps = mAppOpsManager.getPackagesForOps(
new int[]{AppOpsManager.OP_RUN_ANY_IN_BACKGROUND});
final int num = mPackageOps != null ? mPackageOps.size() : 0;
// Enable the preference if some apps already been restricted, otherwise disable it
preference.setEnabled(num > 0);
preference.setSummary(
mContext.getResources().getQuantityString(R.plurals.restricted_app_summary, num,
num));
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (getPreferenceKey().equals(preference.getKey())) {
// start fragment
RestrictedAppDetails.startRestrictedAppDetails(mSettingsActivity, mPreferenceFragment,
mPackageOps);
return true;
}
return super.handlePreferenceTreeClick(preference);
}
}

View File

@@ -0,0 +1,147 @@
/*
* 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.fuelgauge;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.support.v14.preference.PreferenceFragment;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.CheckBoxPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.util.IconDrawableFactory;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.fuelgauge.anomaly.Anomaly;
import com.android.settings.fuelgauge.anomaly.AnomalyDialogFragment;
import com.android.settings.fuelgauge.anomaly.AnomalyPreference;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.List;
/**
* Fragment to show a list of anomaly apps, where user could handle these anomalies
*/
public class RestrictedAppDetails extends DashboardFragment {
public static final String TAG = "RestrictedAppDetails";
private static final String EXTRA_PACKAGE_OPS_LIST = "package_ops_list";
private static final String KEY_PREF_RESTRICTED_APP_LIST = "restrict_app_list";
@VisibleForTesting
List<AppOpsManager.PackageOps> mPackageOpsList;
@VisibleForTesting
IconDrawableFactory mIconDrawableFactory;
@VisibleForTesting
PreferenceGroup mRestrictedAppListGroup;
@VisibleForTesting
BatteryUtils mBatteryUtils;
@VisibleForTesting
PackageManager mPackageManager;
public static void startRestrictedAppDetails(SettingsActivity caller,
PreferenceFragment fragment, List<AppOpsManager.PackageOps> packageOpsList) {
Bundle args = new Bundle();
args.putParcelableList(EXTRA_PACKAGE_OPS_LIST, packageOpsList);
caller.startPreferencePanelAsUser(fragment, RestrictedAppDetails.class.getName(), args,
R.string.restricted_app_title, null /* titleText */,
new UserHandle(UserHandle.myUserId()));
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
final Context context = getContext();
mRestrictedAppListGroup = (PreferenceGroup) findPreference(KEY_PREF_RESTRICTED_APP_LIST);
mPackageOpsList = getArguments().getParcelableArrayList(EXTRA_PACKAGE_OPS_LIST);
mPackageManager = context.getPackageManager();
mIconDrawableFactory = IconDrawableFactory.newInstance(context);
mBatteryUtils = BatteryUtils.getInstance(context);
refreshUi();
}
@Override
public boolean onPreferenceTreeClick(Preference preference) {
return super.onPreferenceTreeClick(preference);
}
@Override
protected String getLogTag() {
return TAG;
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.restricted_apps_detail;
}
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
return null;
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.FUELGAUGE_RESTRICTED_APP_DETAILS;
}
@VisibleForTesting
void refreshUi() {
mRestrictedAppListGroup.removeAll();
final Context context = getPrefContext();
for (int i = 0, size = mPackageOpsList.size(); i < size; i++) {
final CheckBoxPreference checkBoxPreference = new CheckBoxPreference(context);
final AppOpsManager.PackageOps packageOps = mPackageOpsList.get(i);
try {
final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(
packageOps.getPackageName(), 0 /* flags */);
checkBoxPreference.setChecked(true);
checkBoxPreference.setTitle(mPackageManager.getApplicationLabel(applicationInfo));
checkBoxPreference.setKey(packageOps.getPackageName());
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);
return true;
});
mRestrictedAppListGroup.addPreference(checkBoxPreference);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
}
}

View File

@@ -19,9 +19,11 @@ package com.android.settings.fuelgauge;
import android.content.Context;
import android.os.Bundle;
import android.provider.SearchIndexableResource;
import android.support.v14.preference.PreferenceFragment;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -63,14 +65,20 @@ public class SmartBatterySettings extends DashboardFragment {
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
return buildPreferenceControllers(context);
return buildPreferenceControllers(context, (SettingsActivity) getActivity(), this);
}
private static List<AbstractPreferenceController> buildPreferenceControllers(
Context context) {
Context context, SettingsActivity settingsActivity, PreferenceFragment fragment) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new SmartBatteryPreferenceController(context));
controllers.add(new RestrictAppPreferenceController(context));
if (settingsActivity != null && fragment != null) {
controllers.add(
new RestrictAppPreferenceController(settingsActivity, fragment));
} else {
controllers.add(new RestrictAppPreferenceController(context));
}
return controllers;
}
@@ -92,7 +100,7 @@ public class SmartBatterySettings extends DashboardFragment {
@Override
public List<AbstractPreferenceController> getPreferenceControllers(
Context context) {
return buildPreferenceControllers(context);
return buildPreferenceControllers(context, null, null);
}
};
}

View File

@@ -24,7 +24,6 @@ import android.util.SparseIntArray;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
import com.android.settings.fuelgauge.anomaly.action.ForceStopAction;
import com.android.settings.fuelgauge.anomaly.action.LocationCheckAction;
@@ -33,6 +32,7 @@ import com.android.settings.fuelgauge.anomaly.checker.AnomalyDetector;
import com.android.settings.fuelgauge.anomaly.checker.BluetoothScanAnomalyDetector;
import com.android.settings.fuelgauge.anomaly.checker.WakeLockAnomalyDetector;
import com.android.settings.fuelgauge.anomaly.checker.WakeupAlarmAnomalyDetector;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import java.util.ArrayList;
import java.util.List;

View File

@@ -20,9 +20,9 @@ import android.content.Context;
import android.util.Pair;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.fuelgauge.anomaly.Anomaly;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
/**
* Abstract class for anomaly action, which is triggered if we need to handle the anomaly

View File

@@ -0,0 +1,114 @@
/*
* 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.fuelgauge.batterytip;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.android.settings.fuelgauge.anomaly.Anomaly;
/**
* Database controls the anomaly logging(e.g. packageName, anomalyType and time)
*/
public class AnomalyDatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "BatteryDatabaseHelper";
private static final String DATABASE_NAME = "battery_settings.db";
private static final int DATABASE_VERSION = 1;
public interface Tables {
String TABLE_ANOMALY = "anomaly";
}
public interface AnomalyColumns {
/**
* The package name of the anomaly app
*/
String PACKAGE_NAME = "package_name";
/**
* The type of the anomaly app
* @see Anomaly.AnomalyType
*/
String ANOMALY_TYPE = "anomaly_type";
/**
* The time when anomaly happens
*/
String TIME_STAMP_MS = "time_stamp_ms";
}
private static final String CREATE_ANOMALY_TABLE =
"CREATE TABLE " + Tables.TABLE_ANOMALY +
"(" +
AnomalyColumns.PACKAGE_NAME +
" TEXT, " +
AnomalyColumns.ANOMALY_TYPE +
" INTEGER, " +
AnomalyColumns.TIME_STAMP_MS +
" INTEGER)";
private static AnomalyDatabaseHelper sSingleton;
public static synchronized AnomalyDatabaseHelper getInstance(Context context) {
if (sSingleton == null) {
sSingleton = new AnomalyDatabaseHelper(context.getApplicationContext());
}
return sSingleton;
}
private AnomalyDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
bootstrapDB(db);
}
private void bootstrapDB(SQLiteDatabase db) {
db.execSQL(CREATE_ANOMALY_TABLE);
Log.i(TAG, "Bootstrapped database");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < DATABASE_VERSION) {
Log.w(TAG, "Detected schema version '" + oldVersion + "'. " +
"Index needs to be rebuilt for schema version '" + newVersion + "'.");
// We need to drop the tables and recreate them
reconstruct(db);
}
}
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Detected schema version '" + oldVersion + "'. " +
"Index needs to be rebuilt for schema version '" + newVersion + "'.");
// We need to drop the tables and recreate them
reconstruct(db);
}
public void reconstruct(SQLiteDatabase db) {
dropTables(db);
bootstrapDB(db);
}
private void dropTables(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_ANOMALY);
}
}

View File

@@ -0,0 +1,101 @@
/*
* 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.fuelgauge.batterytip;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.VisibleForTesting;
import com.android.settings.fuelgauge.anomaly.Anomaly;
/**
* Model class stores app info(e.g. package name, type..) that used in battery tip
*/
public class AppInfo implements Comparable<AppInfo>, Parcelable {
public final String packageName;
/**
* Anomaly type of the app
* @see Anomaly.AnomalyType
*/
public final int anomalyType;
public final long screenOnTimeMs;
private AppInfo(AppInfo.Builder builder) {
packageName = builder.mPackageName;
anomalyType = builder.mAnomalyType;
screenOnTimeMs = builder.mScreenOnTimeMs;
}
@VisibleForTesting
AppInfo(Parcel in) {
packageName = in.readString();
anomalyType = in.readInt();
screenOnTimeMs = in.readLong();
}
@Override
public int compareTo(AppInfo o) {
return Long.compare(screenOnTimeMs, o.screenOnTimeMs);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(packageName);
dest.writeInt(anomalyType);
dest.writeLong(screenOnTimeMs);
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public AppInfo createFromParcel(Parcel in) {
return new AppInfo(in);
}
public AppInfo[] newArray(int size) {
return new AppInfo[size];
}
};
public static final class Builder {
private int mAnomalyType;
private String mPackageName;
private long mScreenOnTimeMs;
public Builder setAnomalyType(int type) {
mAnomalyType = type;
return this;
}
public Builder setPackageName(String packageName) {
mPackageName = packageName;
return this;
}
public Builder setScreenOnTimeMs(long screenOnTimeMs) {
mScreenOnTimeMs = screenOnTimeMs;
return this;
}
public AppInfo build() {
return new AppInfo(this);
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* 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.fuelgauge.batterytip;
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
.TIME_STAMP_MS;
import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.Tables.TABLE_ANOMALY;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import java.util.ArrayList;
import java.util.List;
/**
* Database manager for battery data. Now it only contains anomaly data stored in {@link AppInfo}.
*/
public class BatteryDatabaseManager {
private final AnomalyDatabaseHelper mDatabaseHelper;
public BatteryDatabaseManager(Context context) {
mDatabaseHelper = AnomalyDatabaseHelper.getInstance(context);
}
/**
* Insert an anomaly log to database.
*
* @param packageName the package name of the app
* @param type the type of the anomaly
* @param timestampMs the time when it is happened
*/
public void insertAnomaly(String packageName, int type, long timestampMs) {
try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) {
ContentValues values = new ContentValues();
values.put(PACKAGE_NAME, packageName);
values.put(ANOMALY_TYPE, type);
values.put(TIME_STAMP_MS, timestampMs);
db.insert(TABLE_ANOMALY, null, values);
}
}
/**
* Query all the anomalies that happened after {@code timestampMs}.
*/
public List<AppInfo> queryAllAnomaliesAfter(long timestampMs) {
final List<AppInfo> appInfos = new ArrayList<>();
try (SQLiteDatabase db = mDatabaseHelper.getReadableDatabase()) {
final String[] projection = {PACKAGE_NAME, ANOMALY_TYPE};
final String orderBy = AnomalyDatabaseHelper.AnomalyColumns.TIME_STAMP_MS + " DESC";
try (Cursor cursor = db.query(TABLE_ANOMALY, projection, TIME_STAMP_MS + " > ?",
new String[]{String.valueOf(timestampMs)}, null, null, orderBy)) {
while (cursor.moveToNext()) {
AppInfo appInfo = new AppInfo.Builder()
.setPackageName(cursor.getString(cursor.getColumnIndex(PACKAGE_NAME)))
.setAnomalyType(cursor.getInt(cursor.getColumnIndex(ANOMALY_TYPE)))
.build();
appInfos.add(appInfo);
}
}
}
return appInfos;
}
public void deleteAllAnomaliesBeforeTimeStamp(long timestampMs) {
try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) {
db.delete(TABLE_ANOMALY, TIME_STAMP_MS + " < ?",
new String[]{String.valueOf(timestampMs)});
}
}
}

View File

@@ -28,6 +28,7 @@ import android.view.LayoutInflater;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController.BatteryTipListener;
import com.android.settings.fuelgauge.batterytip.actions.BatteryTipAction;
@@ -78,7 +79,8 @@ public class BatteryTipDialogFragment extends InstrumentedDialogFragment impleme
return new AlertDialog.Builder(context)
.setMessage(getString(R.string.battery_tip_dialog_message,
highUsageTip.getScreenTimeMs()))
Utils.formatElapsedTime(context, highUsageTip.getScreenTimeMs(),
false /* withSeconds */)))
.setView(view)
.setPositiveButton(android.R.string.ok, null)
.create();

View File

@@ -39,7 +39,7 @@ public class HighUsageAdapter extends RecyclerView.Adapter<HighUsageAdapter.View
private final Context mContext;
private final IconDrawableFactory mIconDrawableFactory;
private final PackageManager mPackageManager;
private final List<HighUsageApp> mHighUsageAppList;
private final List<AppInfo> mHighUsageAppList;
public static class ViewHolder extends RecyclerView.ViewHolder {
public View view;
@@ -56,7 +56,7 @@ public class HighUsageAdapter extends RecyclerView.Adapter<HighUsageAdapter.View
}
}
public HighUsageAdapter(Context context, List<HighUsageApp> highUsageAppList) {
public HighUsageAdapter(Context context, List<AppInfo> highUsageAppList) {
mContext = context;
mHighUsageAppList = highUsageAppList;
mIconDrawableFactory = IconDrawableFactory.newInstance(context);
@@ -72,7 +72,7 @@ public class HighUsageAdapter extends RecyclerView.Adapter<HighUsageAdapter.View
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final HighUsageApp app = mHighUsageAppList.get(position);
final AppInfo app = mHighUsageAppList.get(position);
holder.appIcon.setImageDrawable(
Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager, app.packageName,
UserHandle.myUserId()));

View File

@@ -1,64 +0,0 @@
/*
* 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.fuelgauge.batterytip;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Class representing app with high screen usage
*/
public class HighUsageApp implements Comparable<HighUsageApp>, Parcelable {
public final String packageName;
public final long screenOnTimeMs;
public HighUsageApp(String packageName, long screenOnTimeMs) {
this.packageName = packageName;
this.screenOnTimeMs = screenOnTimeMs;
}
private HighUsageApp(Parcel in) {
packageName = in.readString();
screenOnTimeMs = in.readLong();
}
@Override
public int compareTo(HighUsageApp o) {
return Long.compare(screenOnTimeMs, o.screenOnTimeMs);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(packageName);
dest.writeLong(screenOnTimeMs);
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public HighUsageApp createFromParcel(Parcel in) {
return new HighUsageApp(in);
}
public HighUsageApp[] newArray(int size) {
return new HighUsageApp[size];
}
};
}

View File

@@ -18,7 +18,7 @@ package com.android.settings.fuelgauge.batterytip.actions;
import android.content.Context;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
/**
* Abstract class for battery tip action, which is triggered if we need to handle the battery tip

View File

@@ -22,8 +22,8 @@ import android.support.v14.preference.PreferenceFragment;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.fuelgauge.SmartBatterySettings;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
public class SmartBatteryAction extends BatteryTipAction {
private SettingsActivity mSettingsActivity;

View File

@@ -23,13 +23,11 @@ import android.text.format.DateUtils;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.Utils;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
import com.android.settings.fuelgauge.batterytip.HighUsageApp;
import com.android.settings.fuelgauge.batterytip.AppInfo;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
import com.android.settings.fuelgauge.batterytip.tips.SummaryTip;
import java.util.ArrayList;
import java.util.Collections;
@@ -42,7 +40,7 @@ import java.util.List;
public class HighUsageDetector implements BatteryTipDetector {
private BatteryTipPolicy mPolicy;
private BatteryStatsHelper mBatteryStatsHelper;
private List<HighUsageApp> mHighUsageAppList;
private List<AppInfo> mHighUsageAppList;
private Context mContext;
@VisibleForTesting
BatteryUtils mBatteryUtils;
@@ -68,9 +66,10 @@ public class HighUsageDetector implements BatteryTipDetector {
final long foregroundTimeMs = mBatteryUtils.getProcessTimeMs(
BatteryUtils.StatusType.FOREGROUND, batterySipper.uidObj,
BatteryStats.STATS_SINCE_CHARGED);
mHighUsageAppList.add(new HighUsageApp(
mBatteryUtils.getPackageName(batterySipper.getUid()),
foregroundTimeMs));
mHighUsageAppList.add(new AppInfo.Builder()
.setPackageName(mBatteryUtils.getPackageName(batterySipper.getUid()))
.setScreenOnTimeMs(foregroundTimeMs)
.build());
}
}

View File

@@ -23,7 +23,7 @@ import android.support.annotation.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.fuelgauge.batterytip.HighUsageApp;
import com.android.settings.fuelgauge.batterytip.AppInfo;
import java.util.List;
@@ -34,9 +34,9 @@ public class HighUsageTip extends BatteryTip {
private final long mScreenTimeMs;
@VisibleForTesting
final List<HighUsageApp> mHighUsageAppList;
final List<AppInfo> mHighUsageAppList;
public HighUsageTip(long screenTimeMs, List<HighUsageApp> appList) {
public HighUsageTip(long screenTimeMs, List<AppInfo> appList) {
super(TipType.HIGH_DEVICE_USAGE, appList.isEmpty() ? StateType.INVISIBLE : StateType.NEW,
true /* showDialog */);
mScreenTimeMs = screenTimeMs;
@@ -47,7 +47,7 @@ public class HighUsageTip extends BatteryTip {
HighUsageTip(Parcel in) {
super(in);
mScreenTimeMs = in.readLong();
mHighUsageAppList = in.createTypedArrayList(HighUsageApp.CREATOR);
mHighUsageAppList = in.createTypedArrayList(AppInfo.CREATOR);
}
@Override
@@ -82,7 +82,7 @@ public class HighUsageTip extends BatteryTip {
return mScreenTimeMs;
}
public List<HighUsageApp> getHighUsageAppList() {
public List<AppInfo> getHighUsageAppList() {
return mHighUsageAppList;
}

Some files were not shown because too many files have changed in this diff Show More