Snap for 4949134 from 237f80b0aa to qt-release

Change-Id: I4df85087586fb4187624c2c73052a2199aa4e538
This commit is contained in:
android-build-team Robot
2018-08-12 03:10:13 +00:00
116 changed files with 3121 additions and 2219 deletions

View File

@@ -94,6 +94,7 @@
<uses-permission android:name="android.permission.TEST_BLACKLISTED_PASSWORD" />
<uses-permission android:name="android.permission.USE_RESERVED_DISK" />
<uses-permission android:name="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS" />
<uses-permission android:name="android.permission.CAMERA" />
<application android:label="@string/settings_label"
android:icon="@drawable/ic_launcher_settings"
@@ -201,10 +202,6 @@
android:icon="@drawable/ic_homepage_connected_device"
android:taskAffinity="com.android.settings"
android:parentActivityName="Settings">
<intent-filter android:priority="1">
<action android:name="android.settings.NFC_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.settings.BLUETOOTH_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
@@ -1486,7 +1483,6 @@
<activity
android:name="Settings$TextToSpeechSettingsActivity"
android:label="@string/tts_settings"
android:taskAffinity="com.android.settings"
android:parentActivityName="Settings">
<intent-filter android:priority="1">
<action android:name="com.android.settings.TTS_SETTINGS" />
@@ -1576,9 +1572,17 @@
android:windowSoftInputMode="stateHidden|adjustResize"
android:theme="@style/GlifTheme.Light"/>
<activity android:name=".biometrics.face.FaceEnrollIntroduction" android:exported="false" />
<activity android:name=".biometrics.face.FaceEnrollEnrolling" android:exported="false" />
<activity android:name=".biometrics.face.FaceEnrollFinish" android:exported="false" />
<activity android:name=".biometrics.face.FaceEnrollIntroduction"
android:exported="false"
android:screenOrientation="portrait"/>
<activity android:name=".biometrics.face.FaceEnrollEnrolling"
android:exported="false"
android:screenOrientation="portrait"/>
<activity android:name=".biometrics.face.FaceEnrollFinish"
android:exported="false"
android:screenOrientation="portrait"/>
<activity android:name=".biometrics.fingerprint.FingerprintSettings" android:exported="false"/>
<activity android:name=".biometrics.fingerprint.FingerprintEnrollFindSensor" android:exported="false"/>
@@ -3110,6 +3114,10 @@
android:label="@string/connected_device_connections_title"
android:taskAffinity="com.android.settings"
android:parentActivityName="Settings$ConnectedDeviceDashboardActivity">
<intent-filter android:priority="1">
<action android:name="android.settings.NFC_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="com.android.settings.ADVANCED_CONNECTED_DEVICE_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
@@ -3173,6 +3181,12 @@
<service android:name=".fuelgauge.batterytip.AnomalyDetectionJobService"
android:permission="android.permission.BIND_JOB_SERVICE" />
<provider
android:name=".homepage.CardContentProvider"
android:authorities="com.android.settings.homepage.CardContentProvider"
android:exported="true"
android:permission="android.permission.WRITE_SETTINGS_HOMEPAGE_DATA" />
<!-- This is the longest AndroidManifest.xml ever. -->
</application>
</manifest>

View File

@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
<com.android.settings.fuelgauge.BatteryHistoryChart
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.android.settings"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:id="@+id/battery_history_chart"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
app:headerAppearance="?android:attr/textAppearanceMedium"
android:shadowRadius="4"
android:shadowColor="?android:attr/colorBackground"
android:shadowDx="2"
android:shadowDy="2"
app:barPrimaryColor="?android:attr/colorControlActivated"
app:barPredictionColor="@color/material_empty_color_light"
app:chartMinHeight="@dimen/battery_history_chart_height">
</com.android.settings.fuelgauge.BatteryHistoryChart>
</FrameLayout>

View File

@@ -14,7 +14,7 @@
limitations under the License.
-->
<com.android.settings.dashboard.conditional.FocusRecyclerView
<com.android.settings.homepage.conditional.FocusRecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dashboard_container"
android:layout_width="match_parent"

View File

@@ -39,20 +39,23 @@
android:gravity="center"
android:orientation="vertical">
<com.android.setupwizardlib.view.FillContentLayout
<com.android.settings.biometrics.face.FaceSquareFrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1">
<!-- TODO: replace this with actual content-->
<ImageView
style="@style/SuwContentIllustration"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@null"
android:src="@drawable/face_enroll_introduction" />
<com.android.settings.biometrics.face.FaceSquareTextureView
android:id="@+id/texture_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null" />
</com.android.setupwizardlib.view.FillContentLayout>
<ImageView
android:id="@+id/circle_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.android.settings.biometrics.face.FaceSquareFrameLayout>
<TextView
style="@style/TextAppearance.FaceErrorText"

View File

@@ -15,35 +15,6 @@
-->
<resources>
<declare-styleable name="BatteryHistoryChart">
<!-- Base text color, typeface, size, and style. -->
<attr name="android:textAppearance" />
<!-- Text color. -->
<attr name="android:textColor" />
<!-- Size of the text. Recommended dimension type for text is "sp" for scaled-pixels (example: 15sp). -->
<attr name="android:textSize" />
<!-- Typeface (normal, sans, serif, monospace) for the text. -->
<attr name="android:typeface" />
<!-- Style (bold, italic, bolditalic) for the text. -->
<attr name="android:textStyle" />
<!-- Place a shadow of the specified color behind the text. -->
<attr name="android:shadowColor" />
<!-- Horizontal offset of the shadow. -->
<attr name="android:shadowDx" />
<!-- Vertical offset of the shadow. -->
<attr name="android:shadowDy" />
<!-- Radius of the shadow. -->
<attr name="android:shadowRadius" />
<!-- Text color, typeface, size, and style of header. -->
<attr name="headerAppearance" format="reference" />
<!-- Primary color of chart. -->
<attr name="barPrimaryColor" format="color|reference" />
<!-- Color of predicted future use part of chart. -->
<attr name="barPredictionColor" format="color|reference" />
<!-- Minimum height of the chart itself. -->
<attr name="chartMinHeight" format="dimension|reference" />
</declare-styleable>
<declare-styleable name="PercentageBarChart">
<!-- Background color -->
<attr name="emptyColor" format="color" />

View File

@@ -106,9 +106,6 @@
-->
</string-array>
<!-- Whether or not we should tint the icon color on setting pages. -->
<bool name="config_tintSettingIcon">true</bool>
<!-- Whether or not App & Notification screen should display recently used apps -->
<bool name="config_display_recent_apps">true</bool>
@@ -133,4 +130,7 @@
devices will be able to vary their amplitude but do not possess enough dynamic range to
have distinct intensity levels -->
<bool name="config_vibration_supports_multiple_intensities">false</bool>
<!-- Whether or not TopLevelSettings should force rounded icon for injected tiles -->
<bool name="config_force_rounded_icon_TopLevelSettings">true</bool>
</resources>

View File

@@ -33,8 +33,6 @@
<dimen name="bind_app_widget_dialog_checkbox_bottom_padding">16dip</dimen>
<dimen name="installed_app_details_bullet_offset">8dip</dimen>
<dimen name="battery_history_chart_height">120dp</dimen>
<dimen name="data_usage_chart_height">228dip</dimen>
<dimen name="data_usage_chart_optimalWidth">440dip</dimen>
<dimen name="usage_number_text_size">36sp</dimen>

View File

@@ -161,7 +161,7 @@
<item name="android:navigationBarColor">#00000000</item>
</style>
<style name="Theme.BluetoothPermission" parent="@android:style/Theme.Material.Light.Dialog.Alert">
<style name="Theme.BluetoothPermission" parent="@style/Theme.AlertDialog">
<item name="android:windowNoTitle">true</item>
</style>
@@ -170,6 +170,7 @@
<item name="colorPrimary">@*android:color/primary_device_default_settings_light</item>
<item name="colorPrimaryDark">@*android:color/primary_dark_device_default_settings_light</item>
<item name="colorAccent">@*android:color/accent_device_default_light</item>
<item name="preferenceTheme">@style/PreferenceTheme</item>
</style>
<!--TODO(b/111875856) This theme will be useless, when we add real activity/fragment to handle the full screen for WifiDialog -->

View File

@@ -0,0 +1,46 @@
<?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"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="default_autofill_picker"
android:title="@string/autofill_app"
settings:keywords="@string/autofill_keywords">
<com.android.settings.widget.GearPreference
android:key="default_autofill_main"
android:title="@string/autofill_app"
android:fragment="com.android.settings.applications.defaultapps.DefaultAutofillPicker"
settings:keywords="@string/autofill_keywords">
<extra android:name="for_work" android:value="false" />
</com.android.settings.widget.GearPreference>
<com.android.settings.widget.WorkOnlyCategory
android:key="work_app_defaults"
android:title="@string/default_for_work">
<com.android.settings.widget.GearPreference
android:key="default_autofill_work"
android:title="@string/autofill_app"
android:fragment="com.android.settings.applications.defaultapps.DefaultAutofillPicker"
settings:keywords="@string/autofill_keywords">
<extra android:name="for_work" android:value="true" />
</com.android.settings.widget.GearPreference>
</com.android.settings.widget.WorkOnlyCategory>
</PreferenceScreen>

View File

@@ -54,10 +54,10 @@
android:persistent="false"
android:fragment="com.android.settings.inputmethod.SpellCheckersSettings" />
<com.android.settings.widget.GearPreference
<Preference
android:key="default_autofill"
android:title="@string/autofill_app"
android:fragment="com.android.settings.applications.defaultapps.DefaultAutofillPicker"
android:fragment="com.android.settings.applications.defaultapps.AutofillPicker"
settings:keywords="@string/autofill_keywords" />
<!-- User dictionary preference title and fragment will be set programmatically. -->

View File

@@ -0,0 +1,125 @@
<?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"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="top_level_settings"
android:title="@string/settings_label_launcher">
<Preference
android:key="top_level_network"
android:title="@string/network_dashboard_title"
android:summary="@string/summary_placeholder"
android:icon="@drawable/ic_homepage_network"
android:order="-110"
android:fragment="com.android.settings.network.NetworkDashboardFragment"
settings:controller="com.android.settings.network.TopLevelNetworkEntryPreferenceController"/>
<Preference
android:key="top_level_connected_devices"
android:title="@string/connected_devices_dashboard_title"
android:summary="@string/summary_placeholder"
android:icon="@drawable/ic_homepage_connected_device"
android:order="-100"
android:fragment="com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment"
settings:controller="com.android.settings.connecteddevice.TopLevelConnectedDevicesPreferenceController"/>
<Preference
android:key="top_level_apps_and_notifs"
android:title="@string/app_and_notification_dashboard_title"
android:summary="@string/app_and_notification_dashboard_summary"
android:icon="@drawable/ic_homepage_apps"
android:order="-90"
android:fragment="com.android.settings.applications.AppAndNotificationDashboardFragment"/>
<Preference
android:key="top_level_battery"
android:title="@string/power_usage_summary_title"
android:summary="@string/summary_placeholder"
android:icon="@drawable/ic_homepage_battery"
android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"
android:order="-80"
settings:controller="com.android.settings.fuelgauge.TopLevelBatteryPreferenceController"/>
<Preference
android:key="top_level_display"
android:title="@string/display_settings"
android:summary="@string/display_dashboard_summary"
android:icon="@drawable/ic_homepage_display"
android:order="-70"
android:fragment="com.android.settings.DisplaySettings"/>
<Preference
android:key="top_level_sound"
android:title="@string/sound_settings"
android:summary="@string/sound_dashboard_summary"
android:icon="@drawable/ic_homepage_sound"
android:order="-60"
android:fragment="com.android.settings.notification.SoundSettings"/>
<Preference
android:key="top_level_storage"
android:title="@string/storage_settings"
android:summary="@string/summary_placeholder"
android:icon="@drawable/ic_homepage_storage"
android:order="-50"
android:fragment="com.android.settings.deviceinfo.StorageSettings"
settings:controller="com.android.settings.deviceinfo.TopLevelStoragePreferenceController"/>
<Preference
android:key="top_level_security"
android:title="@string/security_settings_title"
android:summary="@string/summary_placeholder"
android:icon="@drawable/ic_homepage_security"
android:order="-40"
android:fragment="com.android.settings.security.SecuritySettings"
settings:controller="com.android.settings.security.TopLevelSecurityEntryPreferenceController"/>
<Preference
android:key="top_level_accounts"
android:title="@string/account_dashboard_title"
android:summary="@string/summary_placeholder"
android:icon="@drawable/ic_homepage_accounts"
android:order="-30"
android:fragment="com.android.settings.accounts.AccountDashboardFragment"
settings:controller="com.android.settings.accounts.TopLevelAccountEntryPreferenceController"/>
<Preference
android:key="top_level_accessibility"
android:title="@string/accessibility_settings"
android:summary="@string/accessibility_settings_summary"
android:icon="@drawable/ic_homepage_accessibility"
android:order="-20"
android:fragment="com.android.settings.accessibility.AccessibilitySettings"/>
<Preference
android:key="top_level_system"
android:title="@string/header_category_system"
android:summary="@string/system_dashboard_summary"
android:icon="@drawable/ic_homepage_system_dashboard"
android:order="-10"
android:fragment="com.android.settings.system.SystemDashboardFragment"/>
<Preference
android:key="top_level_support"
android:summary="@string/support_summary"
android:title="@string/page_tab_title_support"
android:icon="@drawable/ic_homepage_support"
android:order="100"/>
</PreferenceScreen>

View File

@@ -121,7 +121,6 @@ public class Settings extends SettingsActivity {
}
public static class DirectoryAccessSettingsActivity extends SettingsActivity { /* empty */ }
public static class TopLevelSettings extends SettingsActivity { /* empty */ }
public static class ApnSettingsActivity extends SettingsActivity { /* empty */ }
public static class WifiCallingSettingsActivity extends SettingsActivity { /* empty */ }
public static class MemorySettingsActivity extends SettingsActivity { /* empty */ }

View File

@@ -39,7 +39,6 @@ import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.SubSettingLauncher;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
@@ -82,6 +81,7 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC
};
private final LocalBluetoothManager mLocalBluetoothManager;
private final BluetoothAdapter mBluetoothAdapter;
//cache value of supporting hearing aid or not
private boolean mHearingAidProfileSupported;
private FragmentManager mFragmentManager;
@@ -89,6 +89,7 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC
public AccessibilityHearingAidPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mLocalBluetoothManager = getLocalBluetoothManager();
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mHearingAidProfileSupported = isHearingAidProfileSupported();
}
@@ -151,8 +152,7 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC
if (!mHearingAidProfileSupported) {
return null;
}
final LocalBluetoothAdapter localAdapter = mLocalBluetoothManager.getBluetoothAdapter();
if (!localAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
return null;
}
final List<BluetoothDevice> deviceList = mLocalBluetoothManager.getProfileManager()
@@ -166,8 +166,7 @@ public class AccessibilityHearingAidPreferenceController extends BasePreferenceC
}
private boolean isHearingAidProfileSupported() {
final LocalBluetoothAdapter localAdapter = mLocalBluetoothManager.getBluetoothAdapter();
final List<Integer> supportedList = localAdapter.getSupportedProfiles();
final List<Integer> supportedList = mBluetoothAdapter.getSupportedProfiles();
if (supportedList.contains(BluetoothProfile.HEARING_AID)) {
return true;
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.accounts;
import android.content.Context;
import android.icu.text.ListFormatter;
import android.os.UserHandle;
import android.text.BidiFormatter;
import android.text.TextUtils;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.accounts.AuthenticatorHelper;
import java.util.ArrayList;
import java.util.List;
public class TopLevelAccountEntryPreferenceController extends BasePreferenceController {
public TopLevelAccountEntryPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE_UNSEARCHABLE;
}
@Override
public CharSequence getSummary() {
final AuthenticatorHelper authHelper = new AuthenticatorHelper(mContext,
UserHandle.of(UserHandle.myUserId()), null /* OnAccountsUpdateListener */);
final String[] types = authHelper.getEnabledAccountTypes();
final BidiFormatter bidiFormatter = BidiFormatter.getInstance();
final List<CharSequence> summaries = new ArrayList<>();
if (types == null || types.length == 0) {
summaries.add(mContext.getString(R.string.account_dashboard_default_summary));
} else {
// Show up to 3 account types, ignore any null value
int accountToAdd = Math.min(3, types.length);
for (int i = 0; i < types.length && accountToAdd > 0; i++) {
final CharSequence label = authHelper.getLabelForType(mContext, types[i]);
if (TextUtils.isEmpty(label)) {
continue;
}
summaries.add(bidiFormatter.unicodeWrap(label));
accountToAdd--;
}
}
return ListFormatter.getInstance().format(summaries);
}
}

View File

@@ -16,6 +16,7 @@ package com.android.settings.applications.autofill;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
import android.view.autofill.AutofillManager;
import com.android.settings.applications.defaultapps.DefaultAutofillPicker;
@@ -36,7 +37,8 @@ public class AutofillPickerTrampolineActivity extends Activity {
// First check if the current user's service already belongs to the app...
final Intent intent = getIntent();
final String packageName = intent.getData().getSchemeSpecificPart();
final String currentService = DefaultAutofillPicker.getDefaultKey(this);
final String currentService = DefaultAutofillPicker.getDefaultKey(
this, UserHandle.myUserId());
if (currentService != null && currentService.startsWith(packageName)) {
// ...and succeed right away if it does.
setResult(RESULT_OK);

View File

@@ -0,0 +1,84 @@
/*
* 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.applications.defaultapps;
import android.content.Context;
import android.provider.SearchIndexableResource;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.applications.defaultapps.DefaultAutofillPreferenceController;
import com.android.settings.applications.defaultapps.DefaultWorkAutofillPreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class AutofillPicker extends DashboardFragment {
private static final String TAG = "AutofillPicker";
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DEFAULT_AUTOFILL_PICKER;
}
@Override
protected String getLogTag() {
return TAG;
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.default_autofill_picker_settings;
}
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
return buildPreferenceControllers(context);
}
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
boolean enabled) {
SearchIndexableResource searchIndexableResource =
new SearchIndexableResource(context);
searchIndexableResource.xmlResId = R.xml.default_autofill_picker_settings;
return Arrays.asList(searchIndexableResource);
}
@Override
public List<AbstractPreferenceController> getPreferenceControllers(Context
context) {
return buildPreferenceControllers(context);
}
};
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context) {
return Arrays.asList(
new DefaultAutofillPreferenceController(context),
new DefaultWorkAutofillPreferenceController(context));
}
}

View File

@@ -82,12 +82,16 @@ public abstract class DefaultAppPreferenceController extends AbstractPreferenceC
final Intent settingIntent = getSettingIntent(app);
if (settingIntent != null) {
((GearPreference) preference).setOnGearClickListener(
p -> mContext.startActivity(settingIntent));
p -> startActivity(settingIntent));
} else {
((GearPreference) preference).setOnGearClickListener(null);
}
}
protected void startActivity(Intent intent) {
mContext.startActivity(intent);
}
protected abstract DefaultAppInfo getDefaultAppInfo();
/**

View File

@@ -27,25 +27,23 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.autofill.AutofillService;
import android.service.autofill.AutofillServiceInfo;
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
import androidx.preference.Preference;
import com.android.internal.content.PackageMonitor;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settingslib.applications.DefaultAppInfo;
import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.widget.CandidateInfo;
import java.util.ArrayList;
import java.util.List;
import androidx.preference.Preference;
public class DefaultAutofillPicker extends DefaultAppPickerFragment {
private static final String TAG = "DefaultAutofillPicker";
@@ -73,8 +71,10 @@ public class DefaultAutofillPicker extends DefaultAppPickerFragment {
activity.setResult(Activity.RESULT_CANCELED);
activity.finish();
};
// If mCancelListener is not null, fragment is started from
// ACTION_REQUEST_SET_AUTOFILL_SERVICE and we should always use the calling uid.
mUserId = UserHandle.myUserId();
}
mSettingsPackageMonitor.register(activity, activity.getMainLooper(), false);
update();
}
@@ -159,8 +159,10 @@ public class DefaultAutofillPicker extends DefaultAppPickerFragment {
* @return The preference or {@code null} if no service can be added
*/
private Preference newAddServicePreferenceOrNull() {
final String searchUri = Settings.Secure.getString(getActivity().getContentResolver(),
Settings.Secure.AUTOFILL_SERVICE_SEARCH_URI);
final String searchUri = Settings.Secure.getStringForUser(
getActivity().getContentResolver(),
Settings.Secure.AUTOFILL_SERVICE_SEARCH_URI,
mUserId);
if (TextUtils.isEmpty(searchUri)) {
return null;
}
@@ -189,8 +191,8 @@ public class DefaultAutofillPicker extends DefaultAppPickerFragment {
@Override
protected List<DefaultAppInfo> getCandidates() {
final List<DefaultAppInfo> candidates = new ArrayList<>();
final List<ResolveInfo> resolveInfos = mPm.queryIntentServices(
AUTOFILL_PROBE, PackageManager.GET_META_DATA);
final List<ResolveInfo> resolveInfos = mPm.queryIntentServicesAsUser(
AUTOFILL_PROBE, PackageManager.GET_META_DATA, mUserId);
final Context context = getContext();
for (ResolveInfo info : resolveInfos) {
final String permission = info.serviceInfo.permission;
@@ -210,8 +212,9 @@ public class DefaultAutofillPicker extends DefaultAppPickerFragment {
return candidates;
}
public static String getDefaultKey(Context context) {
String setting = Settings.Secure.getString(context.getContentResolver(), SETTING);
public static String getDefaultKey(Context context, int userId) {
String setting = Settings.Secure.getStringForUser(
context.getContentResolver(), SETTING, userId);
if (setting != null) {
ComponentName componentName = ComponentName.unflattenFromString(setting);
if (componentName != null) {
@@ -223,7 +226,7 @@ public class DefaultAutofillPicker extends DefaultAppPickerFragment {
@Override
protected String getDefaultKey() {
return getDefaultKey(getContext());
return getDefaultKey(getContext(), mUserId);
}
@Override
@@ -239,7 +242,7 @@ public class DefaultAutofillPicker extends DefaultAppPickerFragment {
@Override
protected boolean setDefaultKey(String key) {
Settings.Secure.putString(getContext().getContentResolver(), SETTING, key);
Settings.Secure.putStringForUser(getContext().getContentResolver(), SETTING, key, mUserId);
// Check if activity was launched from Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE
// intent, and set proper result if so...
@@ -263,16 +266,19 @@ public class DefaultAutofillPicker extends DefaultAppPickerFragment {
private final String mSelectedKey;
private final Context mContext;
private final int mUserId;
public AutofillSettingIntentProvider(Context context, String key) {
public AutofillSettingIntentProvider(Context context, int userId, String key) {
mSelectedKey = key;
mContext = context;
mUserId = userId;
}
@Override
public Intent getIntent() {
final List<ResolveInfo> resolveInfos = mContext.getPackageManager().queryIntentServices(
AUTOFILL_PROBE, PackageManager.GET_META_DATA);
final List<ResolveInfo> resolveInfos = mContext.getPackageManager()
.queryIntentServicesAsUser(
AUTOFILL_PROBE, PackageManager.GET_META_DATA, mUserId);
for (ResolveInfo resolveInfo : resolveInfos) {
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;

View File

@@ -44,7 +44,7 @@ public class DefaultAutofillPreferenceController extends DefaultAppPreferenceCon
@Override
public String getPreferenceKey() {
return "default_autofill";
return "default_autofill_main";
}
@Override
@@ -54,7 +54,7 @@ public class DefaultAutofillPreferenceController extends DefaultAppPreferenceCon
}
final DefaultAutofillPicker.AutofillSettingIntentProvider intentProvider =
new DefaultAutofillPicker.AutofillSettingIntentProvider(
mContext, info.getKey());
mContext, mUserId, info.getKey());
return intentProvider.getIntent();
}

View File

@@ -0,0 +1,82 @@
/*
* 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.applications.defaultapps;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import com.android.settings.Utils;
import com.android.settingslib.applications.DefaultAppInfo;
public class DefaultWorkAutofillPreferenceController extends DefaultAutofillPreferenceController {
private final UserHandle mUserHandle;
public DefaultWorkAutofillPreferenceController(Context context) {
super(context);
mUserHandle = Utils.getManagedProfile(mUserManager);
}
@Override
public boolean isAvailable() {
if (mUserHandle == null) {
return false;
}
return super.isAvailable();
}
@Override
public String getPreferenceKey() {
return "default_autofill_work";
}
@Override
protected DefaultAppInfo getDefaultAppInfo() {
final String flattenComponent = Settings.Secure.getStringForUser(
mContext.getContentResolver(),
DefaultAutofillPicker.SETTING,
mUserHandle.getIdentifier());
if (!TextUtils.isEmpty(flattenComponent)) {
DefaultAppInfo appInfo = new DefaultAppInfo(
mContext,
mPackageManager,
mUserHandle.getIdentifier(),
ComponentName.unflattenFromString(flattenComponent));
return appInfo;
}
return null;
}
@Override
protected Intent getSettingIntent(DefaultAppInfo info) {
if (info == null) {
return null;
}
final DefaultAutofillPicker.AutofillSettingIntentProvider intentProvider =
new DefaultAutofillPicker.AutofillSettingIntentProvider(
mContext, mUserHandle.getIdentifier(), info.getKey());
return intentProvider.getIntent();
}
@Override
protected void startActivity(Intent intent) {
mContext.startActivityAsUser(intent, mUserHandle);
}
}

View File

@@ -0,0 +1,85 @@
/*
* 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.biometrics.face;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
/**
* A drawable containing the circle cutout.
*/
public class FaceEnrollAnimationDrawable extends Drawable {
private Rect mBounds;
private final Paint mSquarePaint;
private final Paint mCircleCutoutPaint;
public FaceEnrollAnimationDrawable() {
mSquarePaint = new Paint();
mSquarePaint.setColor(Color.WHITE);
mSquarePaint.setAntiAlias(true);
mCircleCutoutPaint = new Paint();
mCircleCutoutPaint.setColor(Color.TRANSPARENT);
mCircleCutoutPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mCircleCutoutPaint.setAntiAlias(true);
}
@Override
protected void onBoundsChange(Rect bounds) {
mBounds = bounds;
}
@Override
public void draw(Canvas canvas) {
if (mBounds == null) {
return;
}
canvas.save();
// Draw a rectangle covering the whole view
canvas.drawRect(0, 0, mBounds.width(), mBounds.height(), mSquarePaint);
// Clear a circle in the middle for the camera preview
canvas.drawCircle(mBounds.exactCenterX(), mBounds.exactCenterY(),
mBounds.height() / 2, mCircleCutoutPaint);
canvas.restore();
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}

View File

@@ -40,10 +40,12 @@ public class FaceEnrollEnrolling extends BiometricsEnrollEnrolling {
private static final String TAG = "FaceEnrollEnrolling";
private static final boolean DEBUG = true;
private static final String TAG_FACE_PREVIEW = "tag_preview";
private TextView mErrorText;
private Interpolator mLinearOutSlowInInterpolator;
private boolean mShouldFinishOnStop = true;
private FaceEnrollPreviewFragment mFaceCameraPreview;
public static class FaceErrorDialog extends BiometricErrorDialog {
static FaceErrorDialog newInstance(CharSequence msg, int msgId) {
@@ -92,6 +94,18 @@ public class FaceEnrollEnrolling extends BiometricsEnrollEnrolling {
}
}
@Override
public void startEnrollment() {
super.startEnrollment();
mFaceCameraPreview = (FaceEnrollPreviewFragment) getSupportFragmentManager()
.findFragmentByTag(TAG_FACE_PREVIEW);
if (mFaceCameraPreview == null) {
mFaceCameraPreview = new FaceEnrollPreviewFragment();
getSupportFragmentManager().beginTransaction().add(mFaceCameraPreview, TAG_FACE_PREVIEW)
.commitAllowingStateLoss();
}
}
@Override
protected Intent getFinishIntent() {
return new Intent(this, FaceEnrollFinish.class);

View File

@@ -0,0 +1,347 @@
/*
* 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.biometrics.face;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.ImageView;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.InstrumentedPreferenceFragment;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Fragment that contains the logic for showing and controlling the camera preview, circular
* overlay, as well as the enrollment animations.
*/
public class FaceEnrollPreviewFragment extends InstrumentedPreferenceFragment {
private static final String TAG = "FaceEnrollPreviewFragment";
private static final int MAX_PREVIEW_WIDTH = 1920;
private static final int MAX_PREVIEW_HEIGHT = 1080;
private Handler mHandler = new Handler(Looper.getMainLooper());
private CameraManager mCameraManager;
private String mCameraId;
private CameraDevice mCameraDevice;
private CaptureRequest.Builder mPreviewRequestBuilder;
private CameraCaptureSession mCaptureSession;
private CaptureRequest mPreviewRequest;
private Size mPreviewSize;
// View used to contain the circular cutout and enrollment animation drawable
private ImageView mCircleView;
// Drawable containing the circular cutout and enrollment animations
private FaceEnrollAnimationDrawable mAnimationDrawable;
// Texture used for showing the camera preview
private FaceSquareTextureView mTextureView;
private final TextureView.SurfaceTextureListener mSurfaceTextureListener =
new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(
SurfaceTexture surfaceTexture, int width, int height) {
openCamera(width, height);
}
@Override
public void onSurfaceTextureSizeChanged(
SurfaceTexture surfaceTexture, int width, int height) {
// Shouldn't be called, but do this for completeness.
configureTransform(width, height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
};
private final CameraDevice.StateCallback mCameraStateCallback =
new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice cameraDevice) {
mCameraDevice = cameraDevice;
try {
// Configure the size of default buffer
SurfaceTexture texture = mTextureView.getSurfaceTexture();
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
// This is the output Surface we need to start preview
Surface surface = new Surface(texture);
// Set up a CaptureRequest.Builder with the output Surface
mPreviewRequestBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
// Create a CameraCaptureSession for camera preview
mCameraDevice.createCaptureSession(Arrays.asList(surface),
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
// The camera is already closed
if (null == mCameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
mCaptureSession = cameraCaptureSession;
try {
// Auto focus should be continuous for camera preview.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// Finally, we start displaying the camera preview.
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest,
null /* listener */, mHandler);
} catch (CameraAccessException e) {
Log.e(TAG, "Unable to access camera", e);
}
}
@Override
public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
Log.e(TAG, "Unable to configure camera");
}
}, null /* handler */);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onDisconnected(CameraDevice cameraDevice) {
cameraDevice.close();
mCameraDevice = null;
}
@Override
public void onError(CameraDevice cameraDevice, int error) {
cameraDevice.close();
mCameraDevice = null;
}
};
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.FACE_ENROLL_PREVIEW;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTextureView = getActivity().findViewById(R.id.texture_view);
mCircleView = getActivity().findViewById(R.id.circle_view);
// Must disable hardware acceleration for this view, otherwise transparency breaks
mCircleView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
mAnimationDrawable = new FaceEnrollAnimationDrawable();
mCircleView.setImageDrawable(mAnimationDrawable);
mCameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
}
@Override
public void onResume() {
super.onResume();
// When the screen is turned off and turned back on, the SurfaceTexture is already
// available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
// a camera and start preview from here (otherwise, we wait until the surface is ready in
// the SurfaceTextureListener).
if (mTextureView.isAvailable()) {
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
} else {
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
}
@Override
public void onPause() {
super.onPause();
closeCamera();
}
/**
* Sets up member variables related to camera.
*
* @param width The width of available size for camera preview
* @param height The height of available size for camera preview
*/
private void setUpCameraOutputs(int width, int height) {
try {
for (String cameraId : mCameraManager.getCameraIdList()) {
CameraCharacteristics characteristics =
mCameraManager.getCameraCharacteristics(cameraId);
// Find front facing camera
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing == null || facing != CameraCharacteristics.LENS_FACING_FRONT) {
continue;
}
mCameraId = cameraId;
// Get the stream configurations
StreamConfigurationMap map = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
width, height, MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT);
}
} catch (CameraAccessException e) {
Log.e(TAG, "Unable to access camera", e);
}
}
/**
* Opens the camera specified by mCameraId.
* @param width The width of the texture view
* @param height The height of the texture view
*/
private void openCamera(int width, int height) {
try {
setUpCameraOutputs(width, height);
mCameraManager.openCamera(mCameraId, mCameraStateCallback, mHandler);
configureTransform(width, height);
} catch (CameraAccessException e) {
Log.e(TAG, "Unable to open camera", e);
}
}
/**
* Chooses the optimal resolution for the camera to open.
*/
private Size chooseOptimalSize(Size[] choices, int textureViewWidth, int textureViewHeight,
int maxWidth, int maxHeight) {
// Collect the supported resolutions that are at least as big as the preview Surface
List<Size> bigEnough = new ArrayList<>();
// Collect the supported resolutions that are smaller than the preview Surface
List<Size> notBigEnough = new ArrayList<>();
for (Size option : choices) {
if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
option.getHeight() == option.getWidth()) {
if (option.getWidth() >= textureViewWidth &&
option.getHeight() >= textureViewHeight) {
bigEnough.add(option);
} else {
notBigEnough.add(option);
}
}
}
// Pick the smallest of those big enough. If there is no one big enough, pick the
// largest of those not big enough.
if (bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizesByArea());
} else if (notBigEnough.size() > 0) {
return Collections.max(notBigEnough, new CompareSizesByArea());
} else {
Log.e(TAG, "Couldn't find any suitable preview size");
return choices[0];
}
}
/**
* Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
* This method should be called after the camera preview size is determined in
* setUpCameraOutputs and also the size of `mTextureView` is fixed.
*
* @param viewWidth The width of `mTextureView`
* @param viewHeight The height of `mTextureView`
*/
private void configureTransform(int viewWidth, int viewHeight) {
if (mTextureView == null) {
return;
}
// Fix the aspect ratio
Matrix matrix = new Matrix();
float scaleX = (float) viewWidth / mPreviewSize.getWidth();
float scaleY = (float) viewHeight / mPreviewSize.getHeight();
// Now divide by smaller one so it fills up the original space
float smaller = Math.min(scaleX, scaleY);
scaleX = scaleX / smaller;
scaleY = scaleY / smaller;
// Apply the scale
matrix.setScale(scaleX, scaleY);
mTextureView.setTransform(matrix);
}
private void closeCamera() {
if (mCaptureSession != null) {
mCaptureSession.close();
mCaptureSession = null;
}
if (mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
}
/**
* Compares two {@code Size}s based on their areas.
*/
private static class CompareSizesByArea implements Comparator<Size> {
@Override
public int compare(Size lhs, Size rhs) {
// We cast here to ensure the multiplications won't overflow
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
(long) rhs.getWidth() * rhs.getHeight());
}
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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.biometrics.face;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
/**
* Square layout that sets the height to be the same as width.
*/
public class FaceSquareFrameLayout extends FrameLayout {
public FaceSquareFrameLayout(Context context) {
super(context);
}
public FaceSquareFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FaceSquareFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public FaceSquareFrameLayout(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Don't call super, manually set their size below
int size = MeasureSpec.getSize(widthMeasureSpec);
// Set this frame layout to be a square
setMeasuredDimension(size, size);
// Set the children to be the same size (square) as well
final int numChildren = getChildCount();
for (int i = 0; i < numChildren; i++) {
int spec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
this.getChildAt(i).measure(spec, spec);
}
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.settings.biometrics.face;
import android.content.Context;
import android.util.AttributeSet;
import android.view.TextureView;
/**
* A square {@link TextureView}.
*/
public class FaceSquareTextureView extends TextureView {
public FaceSquareTextureView(Context context) {
this(context, null);
}
public FaceSquareTextureView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FaceSquareTextureView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (width < height) {
setMeasuredDimension(width, width);
} else {
setMeasuredDimension(height, height);
}
}
}

View File

@@ -15,6 +15,7 @@
*/
package com.android.settings.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.os.Bundle;
@@ -115,16 +116,30 @@ public abstract class BluetoothDeviceUpdater implements BluetoothCallback,
* Force to update the list of bluetooth devices
*/
public void forceUpdate() {
Collection<CachedBluetoothDevice> cachedDevices =
if (BluetoothAdapter.getDefaultAdapter().isEnabled()) {
final Collection<CachedBluetoothDevice> cachedDevices =
mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
for (CachedBluetoothDevice cachedBluetoothDevice : cachedDevices) {
update(cachedBluetoothDevice);
}
}
}
public void removeAllDevicesFromPreference() {
final Collection<CachedBluetoothDevice> cachedDevices =
mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
for (CachedBluetoothDevice cachedBluetoothDevice : cachedDevices) {
update(cachedBluetoothDevice);
removePreference(cachedBluetoothDevice);
}
}
@Override
public void onBluetoothStateChanged(int bluetoothState) {
forceUpdate();
if (BluetoothAdapter.STATE_ON == bluetoothState) {
forceUpdate();
} else if (BluetoothAdapter.STATE_OFF == bluetoothState) {
removeAllDevicesFromPreference();
}
}
@Override

View File

@@ -37,6 +37,7 @@ import com.android.settings.slices.SliceBuilderUtils;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.ListBuilder.RowBuilder;
import androidx.slice.builders.SliceAction;
/**
@@ -93,7 +94,7 @@ public class BluetoothSliceBuilder {
return new ListBuilder(context, BLUETOOTH_URI, ListBuilder.INFINITY)
.setAccentColor(color)
.addRow(b -> b
.addRow(new RowBuilder()
.setTitle(title)
.addEndItem(toggleSliceAction)
.setPrimaryAction(primarySliceAction))

View File

@@ -32,17 +32,17 @@ import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import androidx.appcompat.app.AlertDialog;
import com.android.settings.R;
import com.android.settingslib.bluetooth.BluetoothDiscoverableTimeoutReceiver;
import androidx.appcompat.app.AlertDialog;
/**
* RequestPermissionActivity asks the user whether to enable discovery. This is
* usually started by an application wanted to start bluetooth and or discovery
*/
public class RequestPermissionActivity extends Activity implements
DialogInterface.OnClickListener {
DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
// Command line to test this
// adb shell am start -a android.bluetooth.adapter.action.REQUEST_ENABLE
// adb shell am start -a android.bluetooth.adapter.action.REQUEST_DISCOVERABLE
@@ -188,6 +188,7 @@ public class RequestPermissionActivity extends Activity implements
builder.setNegativeButton(getString(R.string.deny), this);
}
builder.setOnDismissListener(this);
mDialog = builder.create();
mDialog.show();
}
@@ -238,12 +239,16 @@ public class RequestPermissionActivity extends Activity implements
break;
case DialogInterface.BUTTON_NEGATIVE:
setResult(RESULT_CANCELED);
finish();
cancelAndFinish();
break;
}
}
@Override
public void onDismiss(final DialogInterface dialog) {
cancelAndFinish();
}
private void proceedAndFinish() {
int returnCode;

View File

@@ -0,0 +1,40 @@
/*
* 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.connecteddevice;
import android.content.Context;
import com.android.settings.core.BasePreferenceController;
public class TopLevelConnectedDevicesPreferenceController extends BasePreferenceController {
public TopLevelConnectedDevicesPreferenceController(Context context,
String preferenceKey) {
super(context, preferenceKey);
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE_UNSEARCHABLE;
}
@Override
public CharSequence getSummary() {
return mContext.getText(
AdvancedConnectedDeviceController.getConnectedDevicesSummaryResourceId(mContext));
}
}

View File

@@ -16,7 +16,6 @@
package com.android.settings.dashboard;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
@@ -40,17 +39,17 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.R.id;
import com.android.settings.dashboard.DashboardData.ConditionHeaderData;
import com.android.settings.dashboard.conditional.Condition;
import com.android.settings.dashboard.conditional.ConditionAdapter;
import com.android.settings.dashboard.suggestions.SuggestionAdapter;
import com.android.settings.homepage.conditional.Condition;
import com.android.settings.homepage.conditional.ConditionAdapter;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.RoundedHomepageIcon;
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;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.Tile;
import com.android.settingslib.drawer.TileUtils;
import com.android.settingslib.suggestions.SuggestionControllerMixinCompat;
import com.android.settingslib.utils.IconCache;
@@ -64,7 +63,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
@VisibleForTesting
static final String STATE_CONDITION_EXPANDED = "condition_expanded";
static final String META_DATA_PREFERENCE_ICON_BACKGROUND_ARGB = "com.android.settings.bg.argb";
private final IconCache mCache;
private final Context mContext;
private final MetricsFeatureProvider mMetricsFeatureProvider;
@@ -247,10 +246,6 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
return mDashboardData.getItemEntityById(itemId);
}
public Suggestion getSuggestion(int position) {
return mSuggestionAdapter.getSuggestion(position);
}
@VisibleForTesting
void notifyDashboardDataChanged(DashboardData prevData) {
if (mFirstFrameDrawn && prevData != null) {
@@ -321,31 +316,7 @@ public class DashboardAdapter extends RecyclerView.Adapter<DashboardAdapter.Dash
if (!TextUtils.equals(tileIcon.getResPackage(), mContext.getPackageName())
&& !(icon instanceof RoundedHomepageIcon)) {
icon = new RoundedHomepageIcon(mContext, icon);
final Bundle metaData = tile.getMetaData();
try {
if (metaData != null) {
// Load from bg.argb first
int bgColor = metaData.getInt(META_DATA_PREFERENCE_ICON_BACKGROUND_ARGB,
0 /* default */);
// Not found, load from bg.hint
if (bgColor == 0) {
final int colorRes = metaData.getInt(
TileUtils.META_DATA_PREFERENCE_ICON_BACKGROUND_HINT,
0 /* default */);
if (colorRes != 0) {
bgColor = mContext.getPackageManager()
.getResourcesForApplication(tileIcon.getResPackage())
.getColor(colorRes, null /* theme */);
}
}
// If found anything, use it.
if (bgColor != 0) {
((RoundedHomepageIcon) icon).setBackgroundColor(bgColor);
}
}
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Failed to set background color for " + tile.getPackageName());
}
((RoundedHomepageIcon) icon).setBackgroundColor(mContext, tile);
mCache.updateIcon(tileIcon, icon);
}
holder.icon.setImageDrawable(icon);

View File

@@ -24,7 +24,7 @@ import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.DiffUtil;
import com.android.settings.R;
import com.android.settings.dashboard.conditional.Condition;
import com.android.settings.homepage.conditional.Condition;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.Tile;

View File

@@ -15,8 +15,6 @@
*/
package com.android.settings.dashboard;
import android.content.Context;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.Preference;
@@ -35,34 +33,11 @@ public interface DashboardFeatureProvider {
*/
DashboardCategory getTilesForCategory(String key);
/**
* Get tiles (wrapped as a list of Preference) for key defined in CategoryKey.
*
* @param activity Activity hosting the preference
* @param context UI context to inflate preference
* @param sourceMetricsCategory The context (source) from which an action is performed
* @param key Value from CategoryKey
* @deprecated Pages implementing {@code DashboardFragment} should use
* {@link #getTilesForCategory(String)} instead. Using this method will not get the benefit
* of auto-ordering, progressive disclosure, auto-refreshing summary text etc.
*/
@Deprecated
List<Preference> getPreferencesForCategory(FragmentActivity activity, Context context,
int sourceMetricsCategory, String key);
/**
* Get all tiles, grouped by category.
*/
List<DashboardCategory> getAllCategories();
/**
* Whether or not we should tint icons in setting pages.
*
* @deprecated in favor of color icons in homepage
*/
@Deprecated
boolean shouldTintIcon();
/**
* Returns an unique string key for the tile.
*/
@@ -72,6 +47,7 @@ public interface DashboardFeatureProvider {
* Binds preference to data provided by tile.
*
* @param activity If tile contains intent to launch, it will be launched from this activity
* @param forceRoundedIcon Whether or not injected tiles from other packages should be forced to rounded icon.
* @param sourceMetricsCategory The context (source) from which an action is performed
* @param pref The preference to bind data
* @param tile The binding data
@@ -79,8 +55,8 @@ public interface DashboardFeatureProvider {
* @param baseOrder The order offset value. When binding, pref's order is determined by
* both this value and tile's own priority.
*/
void bindPreferenceToTile(FragmentActivity activity, int sourceMetricsCategory, Preference pref,
Tile tile, String key, int baseOrder);
void bindPreferenceToTile(FragmentActivity activity, boolean forceRoundedIcon,
int sourceMetricsCategory, Preference pref, Tile tile, String key, int baseOrder);
/**
* Returns additional intent filter action for dashboard tiles

View File

@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.IContentProvider;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.provider.Settings;
@@ -42,6 +43,7 @@ import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.dashboard.profileselector.ProfileSelectDialog;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.RoundedHomepageIcon;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.drawer.DashboardCategory;
@@ -49,7 +51,6 @@ import com.android.settingslib.drawer.Tile;
import com.android.settingslib.drawer.TileUtils;
import com.android.settingslib.utils.ThreadUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -80,39 +81,11 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
return mCategoryManager.getTilesByCategory(mContext, key);
}
@Override
public List<Preference> getPreferencesForCategory(FragmentActivity activity, Context context,
int sourceMetricsCategory, String key) {
final DashboardCategory category = getTilesForCategory(key);
if (category == null) {
Log.d(TAG, "NO dashboard tiles for " + TAG);
return null;
}
final List<Tile> tiles = category.getTiles();
if (tiles == null || tiles.isEmpty()) {
Log.d(TAG, "tile list is empty, skipping category " + category.key);
return null;
}
final List<Preference> preferences = new ArrayList<>();
for (Tile tile : tiles) {
final Preference pref = new Preference(context);
bindPreferenceToTile(activity, sourceMetricsCategory, pref, tile, null /* key */,
Preference.DEFAULT_ORDER /* baseOrder */);
preferences.add(pref);
}
return preferences;
}
@Override
public List<DashboardCategory> getAllCategories() {
return mCategoryManager.getCategories(mContext);
}
@Override
public boolean shouldTintIcon() {
return mContext.getResources().getBoolean(R.bool.config_tintSettingIcon);
}
@Override
public String getDashboardKeyForTile(Tile tile) {
if (tile == null) {
@@ -128,8 +101,8 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
}
@Override
public void bindPreferenceToTile(FragmentActivity activity, int sourceMetricsCategory,
Preference pref, Tile tile, String key, int baseOrder) {
public void bindPreferenceToTile(FragmentActivity activity, boolean forceRoundedIcon,
int sourceMetricsCategory, Preference pref, Tile tile, String key, int baseOrder) {
if (pref == null) {
return;
}
@@ -140,7 +113,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
pref.setKey(getDashboardKeyForTile(tile));
}
bindSummary(pref, tile);
bindIcon(pref, tile);
bindIcon(pref, tile, forceRoundedIcon);
final Bundle metadata = tile.getMetaData();
String clsName = null;
String action = null;
@@ -220,10 +193,16 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider {
}
@VisibleForTesting
void bindIcon(Preference preference, Tile tile) {
void bindIcon(Preference preference, Tile tile, boolean forceRoundedIcon) {
final Icon tileIcon = tile.getIcon(mContext);
if (tileIcon != null) {
preference.setIcon(tileIcon.loadDrawable(preference.getContext()));
Drawable iconDrawable = tileIcon.loadDrawable(preference.getContext());
if (forceRoundedIcon
&& !TextUtils.equals(mContext.getPackageName(), tile.getPackageName())) {
iconDrawable = new RoundedHomepageIcon(mContext, iconDrawable);
((RoundedHomepageIcon) iconDrawable).setBackgroundColor(mContext, tile);
}
preference.setIcon(iconDrawable);
} else if (tile.getMetaData() != null
&& tile.getMetaData().containsKey(META_DATA_PREFERENCE_ICON_URI)) {
ThreadUtils.postOnBackgroundThread(() -> {

View File

@@ -207,6 +207,10 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
@Override
protected abstract int getPreferenceScreenResId();
protected boolean shouldForceRoundedIcon() {
return false;
}
protected <T extends AbstractPreferenceController> T use(Class<T> clazz) {
List<AbstractPreferenceController> controllerList = mPreferenceControllers.get(clazz);
if (controllerList != null) {
@@ -343,6 +347,7 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
final int tintColor = a.getColor(0, context.getColor(android.R.color.white));
a.recycle();
// Install dashboard tiles.
final boolean forceRoundedIcons = shouldForceRoundedIcon();
for (Tile tile : tiles) {
final String key = mDashboardFeatureProvider.getDashboardKeyForTile(tile);
if (TextUtils.isEmpty(key)) {
@@ -361,13 +366,15 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment
if (mDashboardTilePrefKeys.contains(key)) {
// Have the key already, will rebind.
final Preference preference = screen.findPreference(key);
mDashboardFeatureProvider.bindPreferenceToTile(getActivity(), getMetricsCategory(),
preference, tile, key, mPlaceholderPreferenceController.getOrder());
mDashboardFeatureProvider.bindPreferenceToTile(getActivity(), forceRoundedIcons,
getMetricsCategory(), preference, tile, key,
mPlaceholderPreferenceController.getOrder());
} else {
// Don't have this key, add it.
final Preference pref = new Preference(getPrefContext());
mDashboardFeatureProvider.bindPreferenceToTile(getActivity(), getMetricsCategory(),
pref, tile, key, mPlaceholderPreferenceController.getOrder());
mDashboardFeatureProvider.bindPreferenceToTile(getActivity(), forceRoundedIcons,
getMetricsCategory(), pref, tile, key,
mPlaceholderPreferenceController.getOrder());
screen.addPreference(pref);
mDashboardTilePrefKeys.add(key);
}

View File

@@ -30,6 +30,7 @@ import com.android.settings.deviceinfo.StorageDashboardFragment;
import com.android.settings.display.NightDisplaySettings;
import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.gestures.GestureSettings;
import com.android.settings.homepage.TopLevelSettings;
import com.android.settings.language.LanguageAndInputSettings;
import com.android.settings.network.NetworkDashboardFragment;
import com.android.settings.notification.ConfigureNotificationSettings;
@@ -61,6 +62,9 @@ public class DashboardFragmentRegistry {
static {
PARENT_TO_CATEGORY_KEY_MAP = new ArrayMap<>();
// TODO(b/110405144): Add the mapping when IA.homepage intent-filter is is removed.
// PARENT_TO_CATEGORY_KEY_MAP.put(TopLevelSettings.class.getName(),
// CategoryKey.CATEGORY_HOMEPAGE);
PARENT_TO_CATEGORY_KEY_MAP.put(
NetworkDashboardFragment.class.getName(), CategoryKey.CATEGORY_NETWORK);
PARENT_TO_CATEGORY_KEY_MAP.put(ConnectedDeviceDashboardFragment.class.getName(),
@@ -98,9 +102,9 @@ public class DashboardFragmentRegistry {
PARENT_TO_CATEGORY_KEY_MAP.put(ZenModeSettings.class.getName(),
CategoryKey.CATEGORY_DO_NOT_DISTURB);
PARENT_TO_CATEGORY_KEY_MAP.put(GestureSettings.class.getName(),
CategoryKey.CATEGORY_GESTURES);
CategoryKey.CATEGORY_GESTURES);
PARENT_TO_CATEGORY_KEY_MAP.put(NightDisplaySettings.class.getName(),
CategoryKey.CATEGORY_NIGHT_DISPLAY);
CategoryKey.CATEGORY_NIGHT_DISPLAY);
CATEGORY_KEY_TO_PARENT_MAP = new ArrayMap<>(PARENT_TO_CATEGORY_KEY_MAP.size());

View File

@@ -26,17 +26,22 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import androidx.loader.app.LoaderManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.core.InstrumentedFragment;
import com.android.settings.core.SettingsBaseActivity;
import com.android.settings.core.SettingsBaseActivity.CategoryListener;
import com.android.settings.dashboard.conditional.Condition;
import com.android.settings.dashboard.conditional.ConditionManager;
import com.android.settings.dashboard.conditional.ConditionManager.ConditionListener;
import com.android.settings.dashboard.conditional.FocusRecyclerView;
import com.android.settings.dashboard.conditional.FocusRecyclerView.FocusListener;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
import com.android.settings.homepage.conditional.Condition;
import com.android.settings.homepage.conditional.ConditionManager;
import com.android.settings.homepage.conditional.ConditionManager.ConditionListener;
import com.android.settings.homepage.conditional.FocusRecyclerView;
import com.android.settings.homepage.conditional.FocusRecyclerView.FocusListener;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.ActionBarShadowController;
import com.android.settingslib.drawer.CategoryKey;
@@ -46,11 +51,12 @@ import com.android.settingslib.utils.ThreadUtils;
import java.util.List;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import androidx.loader.app.LoaderManager;
import androidx.recyclerview.widget.LinearLayoutManager;
/**
* Deprecated in favor of {@link com.android.settings.homepage.TopLevelSettings}
*
* @deprecated
*/
@Deprecated
public class DashboardSummary extends InstrumentedFragment
implements CategoryListener, ConditionListener,
FocusListener, SuggestionControllerMixinCompat.SuggestionControllerHost {

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.deviceinfo;
import android.content.Context;
import android.os.storage.StorageManager;
import android.text.format.Formatter;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.deviceinfo.PrivateStorageInfo;
import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
import java.text.NumberFormat;
public class TopLevelStoragePreferenceController extends BasePreferenceController {
private final StorageManager mStorageManager;
private final StorageManagerVolumeProvider mStorageManagerVolumeProvider;
public TopLevelStoragePreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mStorageManager = mContext.getSystemService(StorageManager.class);
mStorageManagerVolumeProvider = new StorageManagerVolumeProvider(mStorageManager);
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE_UNSEARCHABLE;
}
@Override
public CharSequence getSummary() {
// TODO: Register listener.
final NumberFormat percentageFormat = NumberFormat.getPercentInstance();
final PrivateStorageInfo info = PrivateStorageInfo.getPrivateStorageInfo(
mStorageManagerVolumeProvider);
double privateUsedBytes = info.totalBytes - info.freeBytes;
return mContext.getString(R.string.storage_summary,
percentageFormat.format(privateUsedBytes / info.totalBytes),
Formatter.formatFileSize(mContext, info.freeBytes));
}
}

View File

@@ -42,6 +42,7 @@ import com.android.settings.slices.SliceBroadcastReceiver;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.ListBuilder.RowBuilder;
import androidx.slice.builders.SliceAction;
@@ -93,7 +94,7 @@ public class FlashlightSliceBuilder {
IconCompat.createWithResource(context, R.drawable.ic_signal_flashlight);
return new ListBuilder(context, FLASHLIGHT_URI, ListBuilder.INFINITY)
.setAccentColor(color)
.addRow(b -> b
.addRow(new RowBuilder()
.setTitle(context.getText(R.string.power_flashlight))
.setTitleItem(icon, ICON_IMAGE)
.setPrimaryAction(

File diff suppressed because it is too large Load Diff

View File

@@ -1,126 +0,0 @@
/*
* Copyright (C) 2009 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.content.Intent;
import android.os.BatteryStats;
import android.os.BatteryStats.HistoryItem;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.fuelgauge.BatteryActiveView.BatteryActiveProvider;
import com.android.settings.widget.UsageView;
public class BatteryHistoryDetail extends SettingsPreferenceFragment {
public static final String EXTRA_STATS = "stats";
public static final String EXTRA_BROADCAST = "broadcast";
public static final String BATTERY_HISTORY_FILE = "tmp_bat_history.bin";
private BatteryStats mStats;
private Intent mBatteryBroadcast;
private BatteryFlagParser mChargingParser;
private BatteryFlagParser mScreenOn;
private BatteryFlagParser mGpsParser;
private BatteryFlagParser mFlashlightParser;
private BatteryFlagParser mCameraParser;
private BatteryWifiParser mWifiParser;
private BatteryFlagParser mCpuParser;
private BatteryCellParser mPhoneParser;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
String histFile = getArguments().getString(EXTRA_STATS);
mStats = BatteryStatsHelper.statsFromFile(getActivity(), histFile);
mBatteryBroadcast = getArguments().getParcelable(EXTRA_BROADCAST);
TypedValue value = new TypedValue();
getContext().getTheme().resolveAttribute(android.R.attr.colorAccent, value, true);
int accentColor = getContext().getColor(value.resourceId);
mChargingParser = new BatteryFlagParser(accentColor, false,
HistoryItem.STATE_BATTERY_PLUGGED_FLAG);
mScreenOn = new BatteryFlagParser(accentColor, false,
HistoryItem.STATE_SCREEN_ON_FLAG);
mGpsParser = new BatteryFlagParser(accentColor, false,
HistoryItem.STATE_GPS_ON_FLAG);
mFlashlightParser = new BatteryFlagParser(accentColor, true,
HistoryItem.STATE2_FLASHLIGHT_FLAG);
mCameraParser = new BatteryFlagParser(accentColor, true,
HistoryItem.STATE2_CAMERA_FLAG);
mWifiParser = new BatteryWifiParser(accentColor);
mCpuParser = new BatteryFlagParser(accentColor, false,
HistoryItem.STATE_CPU_RUNNING_FLAG);
mPhoneParser = new BatteryCellParser();
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.battery_history_detail, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
updateEverything();
}
private void updateEverything() {
BatteryInfo.getBatteryInfo(getContext(), info -> {
final View view = getView();
info.bindHistory((UsageView) view.findViewById(R.id.battery_usage), mChargingParser,
mScreenOn, mGpsParser, mFlashlightParser, mCameraParser, mWifiParser,
mCpuParser, mPhoneParser);
((TextView) view.findViewById(R.id.charge)).setText(info.batteryPercentString);
((TextView) view.findViewById(R.id.estimation)).setText(info.remainingLabel);
bindData(mChargingParser, R.string.battery_stats_charging_label, R.id.charging_group);
bindData(mScreenOn, R.string.battery_stats_screen_on_label, R.id.screen_on_group);
bindData(mGpsParser, R.string.battery_stats_gps_on_label, R.id.gps_group);
bindData(mFlashlightParser, R.string.battery_stats_flashlight_on_label,
R.id.flashlight_group);
bindData(mCameraParser, R.string.battery_stats_camera_on_label, R.id.camera_group);
bindData(mWifiParser, R.string.battery_stats_wifi_running_label, R.id.wifi_group);
bindData(mCpuParser, R.string.battery_stats_wake_lock_label, R.id.cpu_group);
bindData(mPhoneParser, R.string.battery_stats_phone_signal_label,
R.id.cell_network_group);
}, mStats, false /* shortString */);
}
private void bindData(BatteryActiveProvider provider, int label, int groupId) {
View group = getView().findViewById(groupId);
group.setVisibility(provider.hasData() ? View.VISIBLE : View.GONE);
((TextView) group.findViewById(android.R.id.title)).setText(label);
((BatteryActiveView) group.findViewById(R.id.battery_active)).setProvider(provider);
}
@Override
public int getMetricsCategory() {
return MetricsEvent.FUELGAUGE_BATTERY_HISTORY_DETAIL;
}
}

View File

@@ -22,19 +22,16 @@ import android.os.Looper;
import android.os.PowerManager;
import android.provider.Settings;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.dashboard.conditional.BatterySaverCondition;
import com.android.settings.dashboard.conditional.ConditionManager;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
public class BatterySaverController extends BasePreferenceController
implements LifecycleObserver, OnStart, OnStop, BatterySaverReceiver.BatterySaverListener {
private static final String KEY_BATTERY_SAVER = "battery_saver_summary";
@@ -82,11 +79,6 @@ public class BatterySaverController extends BasePreferenceController
mBatteryStateChangeReceiver.setListening(false);
}
@VisibleForTesting
void refreshConditionManager() {
ConditionManager.get(mContext).getCondition(BatterySaverCondition.class).refreshState();
}
@Override
public CharSequence getSummary() {
final boolean isPowerSaveOn = mPowerManager.isPowerSaveMode();

View File

@@ -72,8 +72,6 @@ public abstract class PowerUsageBase extends DashboardFragment {
@Override
public void onResume() {
super.onResume();
BatteryStatsHelper.dropFile(getActivity(), BatteryHistoryDetail.BATTERY_HISTORY_FILE);
mBatteryBroadcastReceiver.register();
}

View File

@@ -17,13 +17,13 @@
package com.android.settings.fuelgauge;
import static com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType;
import static com.android.settings.fuelgauge.TopLevelBatteryPreferenceController.getDashboardLabel;
import android.app.Activity;
import android.content.Context;
import android.os.BatteryStats;
import android.os.Bundle;
import android.provider.SearchIndexableResource;
import android.text.BidiFormatter;
import android.text.format.Formatter;
import android.view.Menu;
import android.view.MenuInflater;
@@ -32,6 +32,11 @@ import android.view.View;
import android.view.View.OnLongClickListener;
import android.widget.TextView;
import androidx.annotation.VisibleForTesting;
import androidx.loader.app.LoaderManager;
import androidx.loader.app.LoaderManager.LoaderCallbacks;
import androidx.loader.content.Loader;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
@@ -51,11 +56,6 @@ import com.android.settingslib.utils.StringUtil;
import java.util.Collections;
import java.util.List;
import androidx.annotation.VisibleForTesting;
import androidx.loader.app.LoaderManager;
import androidx.loader.app.LoaderManager.LoaderCallbacks;
import androidx.loader.content.Loader;
/**
* Displays a list of apps and subsystems that consume power, ordered by how much power was
* consumed since the last time it was unplugged.
@@ -147,9 +147,9 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
protected void updateViews(List<BatteryInfo> batteryInfos) {
final BatteryMeterView batteryView = mBatteryLayoutPref
.findViewById(R.id.battery_header_icon);
.findViewById(R.id.battery_header_icon);
final TextView percentRemaining =
mBatteryLayoutPref.findViewById(R.id.battery_percent);
mBatteryLayoutPref.findViewById(R.id.battery_percent);
final TextView summary1 = mBatteryLayoutPref.findViewById(R.id.summary1);
final TextView summary2 = mBatteryLayoutPref.findViewById(R.id.summary2);
BatteryInfo oldInfo = batteryInfos.get(0);
@@ -160,13 +160,13 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
// can sometimes say 0 time remaining because battery stats requires the phone
// be unplugged for a period of time before being willing ot make an estimate.
summary1.setText(mPowerFeatureProvider.getOldEstimateDebugString(
Formatter.formatShortElapsedTime(getContext(),
PowerUtil.convertUsToMs(oldInfo.remainingTimeUs))));
Formatter.formatShortElapsedTime(getContext(),
PowerUtil.convertUsToMs(oldInfo.remainingTimeUs))));
// for this one we can just set the string directly
summary2.setText(mPowerFeatureProvider.getEnhancedEstimateDebugString(
Formatter.formatShortElapsedTime(getContext(),
PowerUtil.convertUsToMs(newInfo.remainingTimeUs))));
Formatter.formatShortElapsedTime(getContext(),
PowerUtil.convertUsToMs(newInfo.remainingTimeUs))));
batteryView.setBatteryLevel(oldInfo.batteryLevel);
batteryView.setCharging(!oldInfo.discharging);
@@ -419,19 +419,6 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList
}
}
@VisibleForTesting
static CharSequence getDashboardLabel(Context context, BatteryInfo info) {
CharSequence label;
final BidiFormatter formatter = BidiFormatter.getInstance();
if (info.remainingLabel == null) {
label = info.batteryPercentString;
} else {
label = context.getString(R.string.power_remaining_settings_home_page,
formatter.unicodeWrap(info.batteryPercentString),
formatter.unicodeWrap(info.remainingLabel));
}
return label;
}
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {

View File

@@ -0,0 +1,90 @@
/*
* 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.content.Context;
import android.text.BidiFormatter;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
public class TopLevelBatteryPreferenceController extends BasePreferenceController implements
LifecycleObserver, OnStart, OnStop {
private final BatteryBroadcastReceiver mBatteryBroadcastReceiver;
private Preference mPreference;
private BatteryInfo mBatteryInfo;
public TopLevelBatteryPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(mContext);
mBatteryBroadcastReceiver.setBatteryChangedListener(type -> {
BatteryInfo.getBatteryInfo(mContext, info -> {
mBatteryInfo = info;
updateState(mPreference);
}, true /* shortString */);
});
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE_UNSEARCHABLE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
}
@Override
public void onStart() {
mBatteryBroadcastReceiver.register();
}
@Override
public void onStop() {
mBatteryBroadcastReceiver.unRegister();
}
@Override
public CharSequence getSummary() {
return getDashboardLabel(mContext, mBatteryInfo);
}
static CharSequence getDashboardLabel(Context context, BatteryInfo info) {
if (info == null || context == null) {
return null;
}
CharSequence label;
final BidiFormatter formatter = BidiFormatter.getInstance();
if (info.remainingLabel == null) {
label = info.batteryPercentString;
} else {
label = context.getString(R.string.power_remaining_settings_home_page,
formatter.unicodeWrap(info.batteryPercentString),
formatter.unicodeWrap(info.remainingLabel));
}
return label;
}
}

View File

@@ -0,0 +1,166 @@
/*
* 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.homepage;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Build;
import android.os.StrictMode;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
/**
* Provider stores and manages user interaction feedback for homepage contextual cards.
*/
public class CardContentProvider extends ContentProvider {
private static final String TAG = "CardContentProvider";
public static final String CARD_AUTHORITY = "com.android.settings.homepage.CardContentProvider";
/** URI matcher for ContentProvider queries. */
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
/** URI matcher type for cards table */
private static final int MATCH_CARDS = 100;
/** URI matcher type for card log table */
private static final int MATCH_CARD_LOG = 200;
static {
sUriMatcher.addURI(CARD_AUTHORITY, CardDatabaseHelper.CARD_TABLE, MATCH_CARDS);
}
private CardDatabaseHelper mDBHelper;
@Override
public boolean onCreate() {
mDBHelper = CardDatabaseHelper.getInstance(getContext());
return true;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
try {
if (Build.IS_DEBUGGABLE) {
enableStrictMode(true);
}
final SQLiteDatabase database = mDBHelper.getWritableDatabase();
final String table = getTableFromMatch(uri);
final long ret = database.insert(table, null, values);
if (ret != -1) {
getContext().getContentResolver().notifyChange(uri, null);
} else {
Log.e(TAG, "The CardContentProvider insertion failed! Plase check SQLiteDatabase's "
+ "message.");
}
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
return uri;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
try {
if (Build.IS_DEBUGGABLE) {
enableStrictMode(true);
}
final SQLiteDatabase database = mDBHelper.getWritableDatabase();
final String table = getTableFromMatch(uri);
final int rowsDeleted = database.delete(table, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}
@Override
public String getType(Uri uri) {
throw new UnsupportedOperationException("getType operation not supported currently.");
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
try {
if (Build.IS_DEBUGGABLE) {
enableStrictMode(true);
}
final SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
final String table = getTableFromMatch(uri);
queryBuilder.setTables(table);
final SQLiteDatabase database = mDBHelper.getReadableDatabase();
final Cursor cursor = queryBuilder.query(database,
projection, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
try {
if (Build.IS_DEBUGGABLE) {
enableStrictMode(true);
}
final SQLiteDatabase database = mDBHelper.getWritableDatabase();
final String table = getTableFromMatch(uri);
final int rowsUpdated = database.update(table, values, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}
private void enableStrictMode(boolean enabled) {
StrictMode.setThreadPolicy(enabled
? new StrictMode.ThreadPolicy.Builder().detectAll().build()
: StrictMode.ThreadPolicy.LAX);
}
@VisibleForTesting
String getTableFromMatch(Uri uri) {
final int match = sUriMatcher.match(uri);
String table;
switch (match) {
case MATCH_CARDS:
table = CardDatabaseHelper.CARD_TABLE;
break;
default:
throw new IllegalArgumentException("Unknown Uri format: " + uri);
}
return table;
}
}

View File

@@ -0,0 +1,190 @@
/*
* 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.homepage;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.VisibleForTesting;
/**
* Defines the schema for the Homepage Cards database.
*/
public class CardDatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "homepage_cards.db";
private static final int DATABASE_VERSION = 1;
public static final String CARD_TABLE = "cards";
public interface CardColumns {
/**
* Primary key. Name of the card.
*/
String NAME = "name";
/**
* Type of the card.
*/
String TYPE = "type";
/**
* Score of the card. Higher numbers have higher priorities.
*/
String SCORE = "score";
/**
* URI of the slice card.
*/
String SLICE_URI = "slice_uri";
/**
* Category of the card. The value is between 0 to 3.
*/
String CATEGORY = "category";
/**
* URI decides the card can be shown.
*/
String AVAILABILITY_URI = "availability_uri";
/**
* Keep the card last display's locale.
*/
String LOCALIZED_TO_LOCALE = "localized_to_locale";
/**
* Package name for all card candidates.
*/
String PACKAGE_NAME = "package_name";
/**
* Application version of the package.
*/
String APP_VERSION = "app_version";
/**
* Title resource name of the package.
*/
String TITLE_RES_NAME = "title_res_name";
/**
* Title of the package to be shown.
*/
String TITLE_TEXT = "title_text";
/**
* Summary resource name of the package.
*/
String SUMMARY_RES_NAME = "summary_res_name";
/**
* Summary of the package to be shown.
*/
String SUMMARY_TEXT = "summary_text";
/**
* Icon resource name of the package.
*/
String ICON_RES_NAME = "icon_res_name";
/**
* Icon resource id of the package.
*/
String ICON_RES_ID = "icon_res_id";
/**
* PendingIntent for for custom view card candidate. Do action when user press card.
*/
String CARD_ACTION = "card_action";
/**
* Expire time of the card. The unit of the value is mini-second.
*/
String EXPIRE_TIME_MS = "expire_time_ms";
}
private static final String CREATE_CARD_TABLE =
"CREATE TABLE " + CARD_TABLE +
"(" +
CardColumns.NAME +
" TEXT NOT NULL PRIMARY KEY, " +
CardColumns.TYPE +
" INTEGER NOT NULL, " +
CardColumns.SCORE +
" DOUBLE NOT NULL, " +
CardColumns.SLICE_URI +
" TEXT, " +
CardColumns.CATEGORY +
" INTEGER DEFAULT 0 CHECK (" +
CardColumns.CATEGORY +
" >= 0 AND " +
CardColumns.CATEGORY +
" <= 3), " +
CardColumns.AVAILABILITY_URI +
" TEXT, " +
CardColumns.LOCALIZED_TO_LOCALE +
" TEXT, " +
CardColumns.PACKAGE_NAME +
" TEXT NOT NULL, " +
CardColumns.APP_VERSION +
" TEXT NOT NULL, " +
CardColumns.TITLE_RES_NAME +
" TEXT, " +
CardColumns.TITLE_TEXT +
" TEXT, " +
CardColumns.SUMMARY_RES_NAME +
" TEXT, " +
CardColumns.SUMMARY_TEXT +
" TEXT, " +
CardColumns.ICON_RES_NAME +
" TEXT, " +
CardColumns.ICON_RES_ID +
" INTEGER DEFAULT 0, " +
CardColumns.CARD_ACTION +
" TEXT, " +
CardColumns.EXPIRE_TIME_MS +
" INTEGER " +
");";
public CardDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_CARD_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + CARD_TABLE);
onCreate(db);
}
}
@VisibleForTesting
static CardDatabaseHelper sCardDatabaseHelper;
public static synchronized CardDatabaseHelper getInstance(Context context) {
if (sCardDatabaseHelper == null) {
sCardDatabaseHelper = new CardDatabaseHelper(context.getApplicationContext());
}
return sCardDatabaseHelper;
}
}

View File

@@ -26,6 +26,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Toolbar;
import androidx.annotation.NonNull;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.SettingsHomepageActivity;
@@ -39,8 +41,6 @@ import com.google.android.material.bottomappbar.BottomAppBar;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import androidx.annotation.NonNull;
public class HomepageFragment extends InstrumentedFragment {
private static final String TAG = "HomepageFragment";
@@ -70,7 +70,7 @@ public class HomepageFragment extends InstrumentedFragment {
private void setupBottomBar() {
final Activity activity = getActivity();
mSearchButton = (FloatingActionButton) activity.findViewById(R.id.search_fab);
mSearchButton = activity.findViewById(R.id.search_fab);
mSearchButton.setOnClickListener(v -> {
final Intent intent = SearchFeatureProvider.SEARCH_UI_INTENT;
@@ -79,7 +79,7 @@ public class HomepageFragment extends InstrumentedFragment {
startActivityForResult(intent, 0 /* requestCode */);
});
mBottomSheetBehavior = BottomSheetBehavior.from(activity.findViewById(R.id.bottom_sheet));
final BottomAppBar bottomBar = (BottomAppBar) activity.findViewById(R.id.bar);
final BottomAppBar bottomBar = activity.findViewById(R.id.bar);
bottomBar.setOnClickListener(v -> {
mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
});
@@ -87,7 +87,7 @@ public class HomepageFragment extends InstrumentedFragment {
final int screenWidthpx = getResources().getDisplayMetrics().widthPixels;
final View searchbar = activity.findViewById(R.id.search_bar_container);
final View bottombar = activity.findViewById(R.id.bar);
final Toolbar searchActionBar = (Toolbar) activity.findViewById(R.id.search_action_bar);
final Toolbar searchActionBar = activity.findViewById(R.id.search_action_bar);
searchActionBar.setNavigationIcon(R.drawable.ic_search_floating_24dp);
@@ -95,6 +95,7 @@ public class HomepageFragment extends InstrumentedFragment {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
if (!mBottomFragmentLoaded) {
// TODO(b/110405144): Switch to {@link TopLevelSettings} when it's ready.
SettingsHomepageActivity.switchToFragment(getActivity(),
R.id.bottom_sheet_fragment, DashboardSummary.class.getName());
mBottomFragmentLoaded = true;

View File

@@ -0,0 +1,116 @@
/*
* 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.homepage;
import static com.android.settings.search.actionbar.SearchMenuController
.NEED_SEARCH_ICON_IN_ACTION_BAR;
import static com.android.settingslib.search.SearchIndexable.MOBILE;
import android.content.Context;
import android.os.Bundle;
import android.provider.SearchIndexableResource;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.search.SearchIndexable;
import java.util.Arrays;
import java.util.List;
@SearchIndexable(forTarget = MOBILE)
public class TopLevelSettings extends DashboardFragment implements
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
private static final String TAG = "TopLevelSettings";
public TopLevelSettings() {
final Bundle args = new Bundle();
// Disable the search icon because this page uses a full search view in actionbar.
args.putBoolean(NEED_SEARCH_ICON_IN_ACTION_BAR, false);
setArguments(args);
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.top_level_settings;
}
@Override
protected String getLogTag() {
return TAG;
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DASHBOARD_SUMMARY;
}
@Override
public int getHelpResource() {
// Disable the help icon because this page uses a full search view in actionbar.
return 0;
}
@Override
public Fragment getCallbackFragment() {
return this;
}
@Override
public boolean onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref) {
new SubSettingLauncher(getActivity())
.setDestination(pref.getFragment())
.setArguments(pref.getExtras())
.setSourceMetricsCategory(caller instanceof Instrumentable
? ((Instrumentable) caller).getMetricsCategory()
: Instrumentable.METRICS_CATEGORY_UNKNOWN)
.setTitleRes(-1)
.launch();
return true;
}
@Override
protected boolean shouldForceRoundedIcon() {
return getContext().getResources()
.getBoolean(R.bool.config_force_rounded_icon_TopLevelSettings);
}
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(
Context context, boolean enabled) {
final SearchIndexableResource sir = new SearchIndexableResource(context);
sir.xmlResId = R.xml.top_level_settings;
return Arrays.asList(sir);
}
@Override
protected boolean isPageSearchEnabled(Context context) {
// Never searchable, all entries in this page are already indexed elsewhere.
return false;
}
};
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.settings.dashboard.conditional;
package com.android.settings.homepage.conditional;
import android.content.BroadcastReceiver;
import android.content.Context;

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.dashboard.conditional;
package com.android.settings.homepage.conditional;
import android.content.BroadcastReceiver;
import android.content.Context;

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.dashboard.conditional;
package com.android.settings.homepage.conditional;
import android.content.Intent;
import android.graphics.drawable.Drawable;

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.dashboard.conditional;
package com.android.settings.homepage.conditional;
import android.content.Intent;
import android.graphics.drawable.Drawable;

View File

@@ -8,7 +8,7 @@
* 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.conditional;
package com.android.settings.homepage.conditional;
import android.content.BroadcastReceiver;
import android.content.Context;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.settings.dashboard.conditional;
package com.android.settings.homepage.conditional;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -22,12 +22,12 @@ import android.content.IntentFilter;
import android.graphics.drawable.Drawable;
import android.os.PersistableBundle;
import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import androidx.annotation.VisibleForTesting;
public abstract class Condition {
private static final String KEY_SILENCE = "silence";

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.dashboard.conditional;
package com.android.settings.homepage.conditional;
import android.content.Context;
import android.util.Log;
@@ -22,6 +22,10 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardAdapter.DashboardItemHolder;
@@ -32,10 +36,6 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import java.util.List;
import java.util.Objects;
import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
public class ConditionAdapter extends RecyclerView.Adapter<DashboardItemHolder> {
public static final String TAG = "ConditionAdapter";

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.dashboard.conditional;
package com.android.settings.homepage.conditional;
import android.content.Context;
import android.os.AsyncTask;
@@ -44,7 +44,7 @@ public class ConditionManager implements LifecycleObserver, OnResume, OnPause {
private static final boolean DEBUG = false;
private static final String PKG = "com.android.settings.dashboard.conditional.";
private static final String PKG = "com.android.settings.homepage.conditional.";
private static final String FILE_NAME = "condition_state.xml";
private static final String TAG_CONDITIONS = "cs";

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.dashboard.conditional;
package com.android.settings.homepage.conditional;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
@@ -26,13 +26,13 @@ import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.ZenModeConfig;
import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.notification.ZenModeSettings;
import androidx.annotation.VisibleForTesting;
public class DndCondition extends Condition {
private static final String TAG = "DndCondition";

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.dashboard.conditional;
package com.android.settings.homepage.conditional;
import android.content.Context;
import android.util.AttributeSet;

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.dashboard.conditional;
package com.android.settings.homepage.conditional;
import android.content.BroadcastReceiver;
import android.content.Context;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.settings.dashboard.conditional;
package com.android.settings.homepage.conditional;
import android.content.Intent;
import android.graphics.drawable.Drawable;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.settings.dashboard.conditional;
package com.android.settings.homepage.conditional;
import static android.content.Context.NOTIFICATION_SERVICE;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.settings.dashboard.conditional;
package com.android.settings.homepage.conditional;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.settings.dashboard.conditional;
package com.android.settings.homepage.conditional;
import android.content.Context;
import android.content.Intent;

View File

@@ -27,10 +27,10 @@ import android.speech.tts.TtsEngines;
import android.text.TextUtils;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.applications.defaultapps.DefaultAutofillPreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.inputmethod.PhysicalKeyboardPreferenceController;
@@ -41,14 +41,10 @@ import com.android.settings.widget.PreferenceCategoryController;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@SearchIndexable
public class LanguageAndInputSettings extends DashboardFragment {
@@ -122,7 +118,6 @@ public class LanguageAndInputSettings extends DashboardFragment {
// Input Assistance
controllers.add(new SpellCheckerPreferenceController(context));
controllers.add(new DefaultAutofillPreferenceController(context));
return controllers;
}

View File

@@ -37,6 +37,7 @@ import com.android.settings.slices.SliceBuilderUtils;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.ListBuilder.RowBuilder;
import androidx.slice.builders.SliceAction;
/**
@@ -70,7 +71,7 @@ public class LocationSliceBuilder {
return new ListBuilder(context, LOCATION_URI, ListBuilder.INFINITY)
.setAccentColor(color)
.addRow(b -> b
.addRow(new RowBuilder()
.setTitle(title)
.setTitleItem(icon, ICON_IMAGE)
.setPrimaryAction(primarySliceAction))

View File

@@ -49,6 +49,7 @@ import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.ListBuilder.RowBuilder;
import androidx.slice.builders.SliceAction;
/**
@@ -183,7 +184,7 @@ public class Enhanced4gLteSliceHelper {
return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
.setAccentColor(Utils.getColorAccentDefaultColor(mContext))
.addRow(b -> b
.addRow(new RowBuilder()
.setTitle(getEnhanced4glteModeTitle(subId))
.addEndItem(
new SliceAction(

View File

@@ -149,6 +149,7 @@ public class NetworkDashboardFragment extends DashboardFragment implements
return 0;
}
// TODO(b/110405144): Remove SummaryProvider
@VisibleForTesting
static class SummaryProvider implements SummaryLoader.SummaryProvider {

View File

@@ -0,0 +1,79 @@
/*
* 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.network;
import android.content.Context;
import android.icu.text.ListFormatter;
import android.text.BidiFormatter;
import android.text.TextUtils;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.wifi.WifiMasterSwitchPreferenceController;
import java.util.ArrayList;
import java.util.List;
public class TopLevelNetworkEntryPreferenceController extends BasePreferenceController {
private final WifiMasterSwitchPreferenceController mWifiPreferenceController;
private final MobileNetworkPreferenceController mMobileNetworkPreferenceController;
private final TetherPreferenceController mTetherPreferenceController;
public TopLevelNetworkEntryPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mMobileNetworkPreferenceController = new MobileNetworkPreferenceController(mContext);
mTetherPreferenceController = new TetherPreferenceController(
mContext, null /* lifecycle */);
mWifiPreferenceController = new WifiMasterSwitchPreferenceController(
mContext, null /* metrics */);
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE_UNSEARCHABLE;
}
@Override
public CharSequence getSummary() {
final String wifiSummary = BidiFormatter.getInstance()
.unicodeWrap(mContext.getString(R.string.wifi_settings_title));
final String mobileSummary = mContext.getString(
R.string.network_dashboard_summary_mobile);
final String dataUsageSummary = mContext.getString(
R.string.network_dashboard_summary_data_usage);
final String hotspotSummary = mContext.getString(
R.string.network_dashboard_summary_hotspot);
final List<String> summaries = new ArrayList<>();
if (mWifiPreferenceController.isAvailable()
&& !TextUtils.isEmpty(wifiSummary)) {
summaries.add(wifiSummary);
}
if (mMobileNetworkPreferenceController.isAvailable() && !TextUtils.isEmpty(mobileSummary)) {
summaries.add(mobileSummary);
}
if (!TextUtils.isEmpty(dataUsageSummary)) {
summaries.add(dataUsageSummary);
}
if (mTetherPreferenceController.isAvailable()
&& !TextUtils.isEmpty(hotspotSummary)) {
summaries.add(hotspotSummary);
}
return ListFormatter.getInstance().format(summaries);
}
}

View File

@@ -40,6 +40,7 @@ import com.android.settings.slices.SliceBuilderUtils;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.ListBuilder.RowBuilder;
import androidx.slice.builders.SliceAction;
public class ZenModeSliceBuilder {
@@ -94,7 +95,7 @@ public class ZenModeSliceBuilder {
return new ListBuilder(context, ZEN_MODE_URI, ListBuilder.INFINITY)
.setAccentColor(color)
.addRow(b -> b
.addRow(new RowBuilder()
.setTitle(title)
.addEndItem(toggleSliceAction)
.setPrimaryAction(primarySliceAction))

View File

@@ -23,6 +23,7 @@ import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
@@ -70,7 +71,7 @@ public class ConfirmDeviceCredentialActivity extends Activity {
KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL);
boolean frp = KeyguardManager.ACTION_CONFIRM_FRP_CREDENTIAL.equals(intent.getAction());
int userId = Utils.getCredentialOwnerUserId(this);
int userId = UserHandle.myUserId();
if (isInternalActivity()) {
try {
userId = Utils.getUserIdFromBundle(this, intent.getExtras());

View File

@@ -125,8 +125,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
mCancelButton = (Button) view.findViewById(R.id.cancelButton);
mFingerprintIcon = (ImageView) view.findViewById(R.id.fingerprintIcon);
mFingerprintHelper = new FingerprintUiHelper(
mFingerprintIcon,
(TextView) view.findViewById(R.id.errorText), this, mEffectiveUserId);
mFingerprintIcon, view.findViewById(R.id.errorText), this, mUserId);
boolean showCancelButton = getActivity().getIntent().getBooleanExtra(
SHOW_CANCEL_BUTTON, false);
boolean hasAlternateButton = mFrp && !TextUtils.isEmpty(mFrpAlternateButtonText);

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.security;
import android.content.Context;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
public class TopLevelSecurityEntryPreferenceController extends BasePreferenceController {
public TopLevelSecurityEntryPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE_UNSEARCHABLE;
}
@Override
public CharSequence getSummary() {
final FingerprintManager fpm =
Utils.getFingerprintManagerOrNull(mContext);
final FaceManager faceManager =
Utils.getFaceManagerOrNull(mContext);
if (faceManager != null && faceManager.isHardwareDetected()) {
return mContext.getText(R.string.security_dashboard_summary_face);
} else if (fpm != null && fpm.isHardwareDetected()) {
return mContext.getText(R.string.security_dashboard_summary);
} else {
return mContext.getText(R.string.security_dashboard_summary_no_fingerprint);
}
}
}

View File

@@ -29,6 +29,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.provider.SettingsSlicesContract;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
@@ -47,12 +48,15 @@ import com.android.settingslib.core.AbstractPreferenceController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.ListBuilder.InputRangeBuilder;
import androidx.slice.builders.ListBuilder.RowBuilder;
import androidx.slice.builders.SliceAction;
@@ -250,11 +254,11 @@ public class SliceBuilderUtils {
(TogglePreferenceController) controller;
final SliceAction sliceAction = getToggleAction(context, sliceData,
toggleController.isChecked());
final List<String> keywords = buildSliceKeywords(sliceData);
final Set<String> keywords = buildSliceKeywords(sliceData);
return new ListBuilder(context, sliceData.getUri(), ListBuilder.INFINITY)
.setAccentColor(color)
.addRow(rowBuilder -> rowBuilder
.addRow(new RowBuilder()
.setTitle(sliceData.getTitle())
.setSubtitle(subtitleText)
.setPrimaryAction(
@@ -270,11 +274,11 @@ public class SliceBuilderUtils {
final IconCompat icon = getSafeIcon(context, sliceData);
final CharSequence subtitleText = getSubtitleText(context, controller, sliceData);
@ColorInt final int color = Utils.getColorAccentDefaultColor(context);
final List<String> keywords = buildSliceKeywords(sliceData);
final Set<String> keywords = buildSliceKeywords(sliceData);
return new ListBuilder(context, sliceData.getUri(), ListBuilder.INFINITY)
.setAccentColor(color)
.addRow(rowBuilder -> rowBuilder
.addRow(new RowBuilder()
.setTitle(sliceData.getTitle())
.setSubtitle(subtitleText)
.setPrimaryAction(
@@ -293,11 +297,11 @@ public class SliceBuilderUtils {
final CharSequence subtitleText = getSubtitleText(context, controller, sliceData);
final SliceAction primaryAction = new SliceAction(contentIntent, icon,
sliceData.getTitle());
final List<String> keywords = buildSliceKeywords(sliceData);
final Set<String> keywords = buildSliceKeywords(sliceData);
return new ListBuilder(context, sliceData.getUri(), ListBuilder.INFINITY)
.setAccentColor(color)
.addInputRange(builder -> builder
.addInputRange(new InputRangeBuilder()
.setTitle(sliceData.getTitle())
.setSubtitle(subtitleText)
.setPrimaryAction(primaryAction)
@@ -343,8 +347,8 @@ public class SliceBuilderUtils {
|| TextUtils.equals(summary, doublePlaceHolder));
}
private static List<String> buildSliceKeywords(SliceData data) {
final List<String> keywords = new ArrayList<>();
private static Set<String> buildSliceKeywords(SliceData data) {
final Set<String> keywords = new ArraySet<>();
keywords.add(data.getTitle());
@@ -366,7 +370,7 @@ public class SliceBuilderUtils {
private static Slice buildUnavailableSlice(Context context, SliceData data) {
final String title = data.getTitle();
final List<String> keywords = buildSliceKeywords(data);
final Set<String> keywords = buildSliceKeywords(data);
@ColorInt final int color = Utils.getColorAccentDefaultColor(context);
final CharSequence summary = context.getText(R.string.disabled_dependent_setting_summary);
final IconCompat icon = IconCompat.createWithResource(context, data.getIconResource());
@@ -375,9 +379,9 @@ public class SliceBuilderUtils {
return new ListBuilder(context, data.getUri(), ListBuilder.INFINITY)
.setAccentColor(color)
.addRow(builder -> builder
.addRow(new RowBuilder()
.setTitle(title)
.setTitleItem(icon)
.setTitleItem(icon, ListBuilder.SMALL_IMAGE)
.setSubtitle(summary)
.setPrimaryAction(primaryAction))
.setKeywords(keywords)

View File

@@ -14,20 +14,26 @@
* limitations under the License.
*/
package com.android.settings.dashboard;
package com.android.settings.widget;
import static androidx.annotation.VisibleForTesting.NONE;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_BACKGROUND_ARGB;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_BACKGROUND_HINT;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Bundle;
import android.util.Log;
import com.android.settings.R;
import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
import com.android.settingslib.drawer.Tile;
public class RoundedHomepageIcon extends LayerDrawable {
private static final String TAG = "RoundedHomepageIcon";
@@ -36,7 +42,7 @@ public class RoundedHomepageIcon extends LayerDrawable {
int mBackgroundColor = -1;
public RoundedHomepageIcon(Context context, Drawable foreground) {
super(new Drawable[] {
super(new Drawable[]{
context.getDrawable(R.drawable.ic_homepage_generic_background),
foreground
});
@@ -45,6 +51,33 @@ public class RoundedHomepageIcon extends LayerDrawable {
setLayerInset(1 /* index */, insetPx, insetPx, insetPx, insetPx);
}
public void setBackgroundColor(Context context, Tile tile) {
final Bundle metaData = tile.getMetaData();
try {
if (metaData != null) {
// Load from bg.argb first
int bgColor = metaData.getInt(META_DATA_PREFERENCE_ICON_BACKGROUND_ARGB,
0 /* default */);
// Not found, load from bg.hint
if (bgColor == 0) {
final int colorRes = metaData.getInt(META_DATA_PREFERENCE_ICON_BACKGROUND_HINT,
0 /* default */);
if (colorRes != 0) {
bgColor = context.getPackageManager()
.getResourcesForApplication(tile.getPackageName())
.getColor(colorRes, null /* theme */);
}
}
// If found anything, use it.
if (bgColor != 0) {
setBackgroundColor(bgColor);
}
}
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Failed to set background color for " + tile.getPackageName());
}
}
public void setBackgroundColor(int color) {
mBackgroundColor = color;
getDrawable(0).setColorFilter(color, PorterDuff.Mode.SRC_ATOP);

View File

@@ -42,6 +42,7 @@ import com.android.settings.slices.SliceBuilderUtils;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.ListBuilder.RowBuilder;
import androidx.slice.builders.SliceAction;
/**
@@ -95,7 +96,7 @@ public class WifiSliceBuilder {
return new ListBuilder(context, WIFI_URI, ListBuilder.INFINITY)
.setAccentColor(color)
.addRow(b -> b
.addRow(new RowBuilder()
.setTitle(title)
.setSubtitle(summary)
.addEndItem(toggleSliceAction)

View File

@@ -209,7 +209,7 @@ public class WifiCallingSliceHelper {
return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
.setAccentColor(Utils.getColorAccentDefaultColor(mContext))
.addRow(b -> b
.addRow(new RowBuilder()
.setTitle(mContext.getText(R.string.wifi_calling_settings_title))
.addEndItem(
new SliceAction(
@@ -298,7 +298,7 @@ public class WifiCallingSliceHelper {
// Top row shows information on current preference state
ListBuilder listBuilder = new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
.setAccentColor(Utils.getColorAccentDefaultColor(mContext));
listBuilder.setHeader(new ListBuilder.HeaderBuilder(listBuilder)
listBuilder.setHeader(new ListBuilder.HeaderBuilder()
.setTitle(mContext.getText(R.string.wifi_calling_mode_title))
.setSubtitle(getWifiCallingPreferenceSummary(currentWfcPref))
.setPrimaryAction(new SliceAction(
@@ -338,7 +338,7 @@ public class WifiCallingSliceHelper {
int preferenceTitleResId, String action, boolean checked) {
final IconCompat icon =
IconCompat.createWithResource(mContext, R.drawable.radio_button_check);
return new RowBuilder(listBuilder)
return new RowBuilder()
.setTitle(mContext.getText(preferenceTitleResId))
.setTitleItem(new SliceAction(getBroadcastIntent(action),
icon, mContext.getText(preferenceTitleResId), checked));
@@ -488,7 +488,7 @@ public class WifiCallingSliceHelper {
final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
.setAccentColor(Utils.getColorAccentDefaultColor(mContext))
.addRow(b -> b
.addRow(new RowBuilder()
.setTitle(title)
.setSubtitle(subtitle)
.setPrimaryAction(new SliceAction(

View File

@@ -39,7 +39,6 @@ com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionMi
com.android.settings.enterprise.ApplicationListFragment$EnterpriseInstalledPackages
com.android.settings.enterprise.EnterpriseSetDefaultAppsListFragment
com.android.settings.fuelgauge.AdvancedPowerUsageDetail
com.android.settings.fuelgauge.BatteryHistoryDetail
com.android.settings.fuelgauge.InactiveApps
com.android.settings.fuelgauge.RestrictedAppDetails
com.android.settings.IccLockSettings

View File

@@ -15,7 +15,6 @@
-->
<resources>
<bool name="config_tintSettingIcon">false</bool>
<bool name="config_enableColorTemperature">false</bool>
<bool name="config_show_camera_laser_sensor">false</bool>
<bool name="config_show_connectivity_monitor">false</bool>

View File

@@ -40,10 +40,10 @@ import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -55,23 +55,24 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothUtils.class})
@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class})
public class AccessibilityHearingAidPreferenceControllerTest {
private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
private static final String TEST_DEVICE_NAME = "TEST_HEARING_AID_BT_DEVICE_NAME";
private static final String HEARING_AID_PREFERENCE = "hearing_aid_preference";
private BluetoothAdapter mBluetoothAdapter;
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
private BluetoothManager mBluetoothManager;
private BluetoothDevice mBluetoothDevice;
private Context mContext;
private Preference mHearingAidPreference;
private List<Integer> mProfileSupportedList;
private AccessibilityHearingAidPreferenceController mPreferenceController;
@Mock
@@ -79,8 +80,6 @@ public class AccessibilityHearingAidPreferenceControllerTest {
@Mock
private CachedBluetoothDeviceManager mCachedDeviceManager;
@Mock
private LocalBluetoothAdapter mLocalBluetoothAdapter;
@Mock
private LocalBluetoothManager mLocalBluetoothManager;
@Mock
private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
@@ -161,7 +160,7 @@ public class AccessibilityHearingAidPreferenceControllerTest {
@Test
public void onNotSupportHearingAidProfile_doNotDoReceiverOperation() {
//clear bluetooth supported profile
mProfileSupportedList.clear();
mShadowBluetoothAdapter.clearSupportedProfiles();
mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext, HEARING_AID_PREFERENCE);
mPreferenceController.setPreference(mHearingAidPreference);
//not call registerReceiver()
@@ -178,18 +177,17 @@ public class AccessibilityHearingAidPreferenceControllerTest {
mLocalBluetoothManager = ShadowBluetoothUtils.getLocalBtManager(mContext);
mBluetoothManager = new BluetoothManager(mContext);
mBluetoothAdapter = mBluetoothManager.getAdapter();
when(mLocalBluetoothManager.getBluetoothAdapter()).thenReturn(mLocalBluetoothAdapter);
when(mLocalBluetoothAdapter.isEnabled()).thenReturn(true);
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
}
private void setupHearingAidEnvironment() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
mProfileSupportedList = new ArrayList<Integer>();
mProfileSupportedList.add(BluetoothProfile.HEARING_AID);
when(mLocalBluetoothAdapter.getSupportedProfiles()).thenReturn(mProfileSupportedList);
mShadowBluetoothAdapter.enable();
mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
when(mCachedBluetoothDevice.getName()).thenReturn(TEST_DEVICE_NAME);
when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);

View File

@@ -15,40 +15,20 @@
*/
package com.android.settings.accounts;
import static com.android.settings.accounts.AccountDashboardFragmentTest
.ShadowAuthenticationHelper.LABELS;
import static com.android.settings.accounts.AccountDashboardFragmentTest
.ShadowAuthenticationHelper.TYPES;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.os.UserHandle;
import android.provider.SearchIndexableResource;
import android.text.TextUtils;
import com.android.settings.R;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.testutils.Robolectric;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.accounts.AuthenticatorHelper;
import com.android.settingslib.drawer.CategoryKey;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import java.util.List;
import androidx.fragment.app.FragmentActivity;
@RunWith(SettingsRobolectricTestRunner.class)
public class AccountDashboardFragmentTest {
@@ -59,66 +39,11 @@ public class AccountDashboardFragmentTest {
mFragment = new AccountDashboardFragment();
}
@After
public void tearDown() {
ShadowAuthenticationHelper.reset();
}
@Test
public void testCategory_isAccount() {
assertThat(mFragment.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_ACCOUNT);
}
@Test
@Config(shadows = {
ShadowAuthenticationHelper.class
})
public void updateSummary_hasAccount_shouldDisplayUpTo3AccountTypes() {
final SummaryLoader loader = mock(SummaryLoader.class);
final FragmentActivity activity = Robolectric.buildActivity(
FragmentActivity.class).setup().get();
final SummaryLoader.SummaryProvider provider =
AccountDashboardFragment.SUMMARY_PROVIDER_FACTORY.createSummaryProvider(activity,
loader);
provider.setListening(true);
verify(loader).setSummary(provider, LABELS[0] + ", " + LABELS[1] + ", and " + LABELS[2]);
}
@Test
@Config(shadows = ShadowAuthenticationHelper.class)
public void updateSummary_noAccount_shouldDisplayDefaultSummary() {
ShadowAuthenticationHelper.setEnabledAccount(null);
final SummaryLoader loader = mock(SummaryLoader.class);
final FragmentActivity activity = Robolectric.buildActivity(FragmentActivity.class).setup().get();
final SummaryLoader.SummaryProvider provider =
AccountDashboardFragment.SUMMARY_PROVIDER_FACTORY.createSummaryProvider(activity,
loader);
provider.setListening(true);
verify(loader).setSummary(provider,
activity.getString(R.string.account_dashboard_default_summary));
}
@Test
@Config(shadows = ShadowAuthenticationHelper.class)
public void updateSummary_noAccountTypeLabel_shouldNotDisplayNullEntry() {
final SummaryLoader loader = mock(SummaryLoader.class);
final FragmentActivity activity = Robolectric.buildActivity(FragmentActivity.class).setup().get();
final String[] enabledAccounts = {TYPES[0], "unlabeled_account_type", TYPES[1]};
ShadowAuthenticationHelper.setEnabledAccount(enabledAccounts);
final SummaryLoader.SummaryProvider provider =
AccountDashboardFragment.SUMMARY_PROVIDER_FACTORY.createSummaryProvider(activity,
loader);
provider.setListening(true);
// should only show the 2 accounts with labels
verify(loader).setSummary(provider, LABELS[0] + " and " + LABELS[1]);
}
@Test
public void testSearchIndexProvider_shouldIndexResource() {
final List<SearchIndexableResource> indexRes =
@@ -129,43 +54,5 @@ public class AccountDashboardFragmentTest {
assertThat(indexRes.get(0).xmlResId).isEqualTo(mFragment.getPreferenceScreenResId());
}
@Implements(AuthenticatorHelper.class)
public static class ShadowAuthenticationHelper {
static final String[] TYPES = {"type1", "type2", "type3", "type4"};
static final String[] LABELS = {"LABEL1", "LABEL2", "LABEL3", "LABEL4"};
private static String[] sEnabledAccount = TYPES;
public void __constructor__(Context context, UserHandle userHandle,
AuthenticatorHelper.OnAccountsUpdateListener listener) {
}
private static void setEnabledAccount(String[] enabledAccount) {
sEnabledAccount = enabledAccount;
}
@Resetter
public static void reset() {
sEnabledAccount = TYPES;
}
@Implementation
public String[] getEnabledAccountTypes() {
return sEnabledAccount;
}
@Implementation
public CharSequence getLabelForType(Context context, final String accountType) {
if (TextUtils.equals(accountType, TYPES[0])) {
return LABELS[0];
} else if (TextUtils.equals(accountType, TYPES[1])) {
return LABELS[1];
} else if (TextUtils.equals(accountType, TYPES[2])) {
return LABELS[2];
} else if (TextUtils.equals(accountType, TYPES[3])) {
return LABELS[3];
}
return null;
}
}
}

View File

@@ -130,7 +130,7 @@ public class AccountDetailDashboardFragmentTest {
final FragmentActivity activity = Robolectric.setupActivity(FragmentActivity.class);
final Preference preference = new Preference(mContext);
dashboardFeatureProvider.bindPreferenceToTile(activity,
dashboardFeatureProvider.bindPreferenceToTile(activity, false /* forceRoundedIcon */,
MetricsProto.MetricsEvent.DASHBOARD_SUMMARY, preference, tile, null /* key */,
Preference.DEFAULT_ORDER);

View File

@@ -0,0 +1,126 @@
/*
* 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.accounts;
import static com.android.settings.accounts.TopLevelAccountEntryPreferenceControllerTest
.ShadowAuthenticationHelper.LABELS;
import static com.android.settings.accounts.TopLevelAccountEntryPreferenceControllerTest
.ShadowAuthenticationHelper.TYPES;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.UserHandle;
import android.text.TextUtils;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.accounts.AuthenticatorHelper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = {TopLevelAccountEntryPreferenceControllerTest.ShadowAuthenticationHelper.class})
public class TopLevelAccountEntryPreferenceControllerTest {
private TopLevelAccountEntryPreferenceController mController;
private Context mContext;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mController = new TopLevelAccountEntryPreferenceController(mContext, "test_key");
}
@After
public void tearDown() {
ShadowAuthenticationHelper.reset();
}
@Test
public void updateSummary_hasAccount_shouldDisplayUpTo3AccountTypes() {
assertThat(mController.getSummary())
.isEqualTo(LABELS[0] + ", " + LABELS[1] + ", and " + LABELS[2]);
}
@Test
public void updateSummary_noAccount_shouldDisplayDefaultSummary() {
ShadowAuthenticationHelper.setEnabledAccount(null);
assertThat(mController.getSummary()).isEqualTo(
mContext.getText(R.string.account_dashboard_default_summary));
}
@Test
public void updateSummary_noAccountTypeLabel_shouldNotDisplayNullEntry() {
final String[] enabledAccounts = {TYPES[0], "unlabeled_account_type", TYPES[1]};
ShadowAuthenticationHelper.setEnabledAccount(enabledAccounts);
// should only show the 2 accounts with labels
assertThat(mController.getSummary()).isEqualTo(LABELS[0] + " and " + LABELS[1]);
}
@Implements(AuthenticatorHelper.class)
public static class ShadowAuthenticationHelper {
static final String[] TYPES = {"type1", "type2", "type3", "type4"};
static final String[] LABELS = {"LABEL1", "LABEL2", "LABEL3", "LABEL4"};
private static String[] sEnabledAccount = TYPES;
public void __constructor__(Context context, UserHandle userHandle,
AuthenticatorHelper.OnAccountsUpdateListener listener) {
}
private static void setEnabledAccount(String[] enabledAccount) {
sEnabledAccount = enabledAccount;
}
@Resetter
public static void reset() {
sEnabledAccount = TYPES;
}
@Implementation
public String[] getEnabledAccountTypes() {
return sEnabledAccount;
}
@Implementation
public CharSequence getLabelForType(Context context, final String accountType) {
if (TextUtils.equals(accountType, TYPES[0])) {
return LABELS[0];
} else if (TextUtils.equals(accountType, TYPES[1])) {
return LABELS[1];
} else if (TextUtils.equals(accountType, TYPES[2])) {
return LABELS[2];
} else if (TextUtils.equals(accountType, TYPES[3])) {
return LABELS[3];
}
return null;
}
}
}

View File

@@ -17,65 +17,196 @@
package com.android.settings.applications.defaultapps;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.RuntimeEnvironment.application;
import android.app.Activity;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceScreen;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settings.testutils.shadow.ShadowProcess;
import com.android.settings.testutils.shadow.ShadowSecureSettings;
import com.android.settingslib.applications.DefaultAppInfo;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = {
SettingsShadowResources.SettingsShadowTheme.class,
ShadowProcess.class,
ShadowSecureSettings.class
})
public class DefaultAutofillPickerTest {
private static final String TEST_APP_KEY = "foo.bar/foo.bar.Baz";
private static final String MAIN_APP_KEY = "main.foo.bar/foo.bar.Baz";
private static final String MANAGED_APP_KEY = "managed.foo.bar/foo.bar.Baz";
private static final int MANAGED_PROFILE_UID = 10;
private static final int MAIN_PROFILE_UID = 0;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Activity mActivity;
private FragmentActivity mActivity;
@Mock
private UserManager mUserManager;
@Mock
private AppOpsManager mAppOpsManager;
@Mock
private PackageManager mPackageManager;
@Mock
private PreferenceScreen mScreen;
private DefaultAutofillPicker mPicker;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
FakeFeatureFactory.setupForTest();
Resources res = application.getResources();
when(mActivity.getApplicationContext()).thenReturn(mActivity);
when(mActivity.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
when(mActivity.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
when(mActivity.getTheme()).thenReturn(res.newTheme());
when(mActivity.getResources()).thenReturn(res);
mPicker = spy(new DefaultAutofillPicker());
mPicker.onAttach((Context) mActivity);
doReturn(application.getApplicationContext()).when(mPicker).getContext();
doReturn(mActivity).when(mPicker).getActivity();
doReturn(res).when(mPicker).getResources();
doReturn(mScreen).when(mPicker).getPreferenceScreen();
doNothing().when(mPicker).onCreatePreferences(any(), any());
doNothing().when(mPicker).updateCandidates();
ReflectionHelpers.setField(mPicker, "mPm", mPackageManager);
doReturn(RuntimeEnvironment.application).when(mPicker).getContext();
}
@Test
public void setAndGetDefaultAppKey_shouldUpdateDefaultAutoFill() {
assertThat(mPicker.setDefaultKey(TEST_APP_KEY)).isTrue();
assertThat(mPicker.getDefaultKey()).isEqualTo(TEST_APP_KEY);
mPicker.onAttach((Context) mActivity);
ReflectionHelpers.setField(
mPicker, "mUserId", MAIN_PROFILE_UID * UserHandle.PER_USER_RANGE);
assertThat(mPicker.setDefaultKey(MAIN_APP_KEY)).isTrue();
ReflectionHelpers.setField(
mPicker, "mUserId", MANAGED_PROFILE_UID * UserHandle.PER_USER_RANGE);
assertThat(mPicker.setDefaultKey(MANAGED_APP_KEY)).isTrue();
ReflectionHelpers.setField(
mPicker, "mUserId", MAIN_PROFILE_UID * UserHandle.PER_USER_RANGE);
assertThat(mPicker.getDefaultKey()).isEqualTo(MAIN_APP_KEY);
ReflectionHelpers.setField(
mPicker, "mUserId", MANAGED_PROFILE_UID * UserHandle.PER_USER_RANGE);
assertThat(mPicker.getDefaultKey()).isEqualTo(MANAGED_APP_KEY);
}
@Test
public void getConfirmationMessage_shouldNotBeNull() {
mPicker.onAttach((Context) mActivity);
final DefaultAppInfo info = mock(DefaultAppInfo.class);
when(info.loadLabel()).thenReturn("test_app_name");
assertThat(mPicker.getConfirmationMessage(info)).isNotNull();
}
@Test
public void mUserId_shouldDeriveUidFromManagedCaller() {
setupUserManager();
setupCaller();
ShadowProcess.setMyUid(MANAGED_PROFILE_UID * UserHandle.PER_USER_RANGE);
mPicker.onAttach((Context) mActivity);
mPicker.onCreate(null);
assertUserId(MANAGED_PROFILE_UID);
}
@Test
public void mUserId_shouldDeriveUidFromMainCaller() {
setupUserManager();
setupCaller();
ShadowProcess.setMyUid(MAIN_PROFILE_UID * UserHandle.PER_USER_RANGE);
mPicker.onAttach((Context) mActivity);
mPicker.onCreate(null);
assertUserId(MAIN_PROFILE_UID);
}
@Test
public void mUserId_shouldDeriveUidFromManagedClick() {
setupUserManager();
setupClick(/* forWork= */ true);
ShadowProcess.setMyUid(MAIN_PROFILE_UID * UserHandle.PER_USER_RANGE);
mPicker.onAttach((Context) mActivity);
mPicker.onCreate(null);
assertUserId(MANAGED_PROFILE_UID);
}
@Test
public void mUserId_shouldDeriveUidFromMainClick() {
setupUserManager();
setupClick(/* forWork= */ false);
ShadowProcess.setMyUid(MAIN_PROFILE_UID * UserHandle.PER_USER_RANGE);
mPicker.onAttach((Context) mActivity);
mPicker.onCreate(null);
assertUserId(MAIN_PROFILE_UID);
}
private void setupUserManager() {
UserHandle mainUserHandle = new UserHandle(MAIN_PROFILE_UID);
UserHandle managedUserHandle = new UserHandle(MANAGED_PROFILE_UID);
UserInfo managedUserInfo = new UserInfo(
MANAGED_PROFILE_UID, "managed", UserInfo.FLAG_MANAGED_PROFILE);
when(mUserManager.getUserProfiles())
.thenReturn(Arrays.asList(mainUserHandle, managedUserHandle));
when(mUserManager.getUserInfo(MANAGED_PROFILE_UID))
.thenReturn(managedUserInfo);
when(mUserManager.getUserHandle()).thenReturn(MAIN_PROFILE_UID);
}
private void setupCaller() {
Intent intent = new Intent();
intent.putExtra("package_name", "any package name");
when(mActivity.getIntent()).thenReturn(intent);
}
private void setupClick(boolean forWork) {
Bundle bundle = new Bundle();
bundle.putBoolean("for_work", forWork);
doReturn(bundle).when(mPicker).getArguments();
}
private void assertUserId(int userId) {
assertThat((Integer) ReflectionHelpers.getField(mPicker, "mUserId"))
.isEqualTo(userId);
}
}

View File

@@ -22,6 +22,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
@@ -31,6 +32,7 @@ import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowAudioManager;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.HeadsetProfile;
@@ -44,12 +46,13 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import java.util.ArrayList;
import java.util.Collection;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = {ShadowAudioManager.class})
@Config(shadows = {ShadowAudioManager.class, ShadowBluetoothAdapter.class})
public class AvailableMediaBluetoothDeviceUpdaterTest {
@Mock
private DashboardFragment mDashboardFragment;
@@ -73,12 +76,15 @@ public class AvailableMediaBluetoothDeviceUpdaterTest {
private Collection<CachedBluetoothDevice> cachedDevices;
private ShadowAudioManager mShadowAudioManager;
private BluetoothDevicePreference mPreference;
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mShadowAudioManager = ShadowAudioManager.getShadow();
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
mShadowBluetoothAdapter.setEnabled(true);
mContext = RuntimeEnvironment.application;
doReturn(mContext).when(mDashboardFragment).getContext();
cachedDevices =

View File

@@ -22,15 +22,19 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import androidx.preference.Preference;
import com.android.settings.SettingsActivity;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import org.junit.Before;
@@ -40,10 +44,14 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import androidx.preference.Preference;
import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothAdapter.class})
public class BluetoothDeviceUpdaterTest {
@Mock
@@ -58,18 +66,26 @@ public class BluetoothDeviceUpdaterTest {
private SettingsActivity mSettingsActivity;
@Mock
private LocalBluetoothManager mLocalManager;
@Mock
private CachedBluetoothDeviceManager mCachedDeviceManager;
private Context mContext;
private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
private BluetoothDevicePreference mPreference;
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
private List<CachedBluetoothDevice> mCachedDevices = new ArrayList<CachedBluetoothDevice>();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
mCachedDevices.add(mCachedBluetoothDevice);
doReturn(mContext).when(mDashboardFragment).getContext();
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
when(mLocalManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices);
mPreference = new BluetoothDevicePreference(mContext, mCachedBluetoothDevice, false);
mBluetoothDeviceUpdater =
@@ -171,4 +187,38 @@ public class BluetoothDeviceUpdaterTest {
// Shouldn't crash
mBluetoothDeviceUpdater.unregisterCallback();
}
@Test
public void forceUpdate_bluetoothDisabled_doNothing() {
mShadowBluetoothAdapter.setEnabled(false);
mBluetoothDeviceUpdater.forceUpdate();
verify(mDevicePreferenceCallback, never()).onDeviceAdded(any(Preference.class));
}
@Test
public void forceUpdate_bluetoothEnabled_addPreference() {
mShadowBluetoothAdapter.setEnabled(true);
mBluetoothDeviceUpdater.forceUpdate();
verify(mDevicePreferenceCallback).onDeviceAdded(any(Preference.class));
}
@Test
public void onBluetoothStateChanged_bluetoothStateIsOn_forceUpdate() {
mShadowBluetoothAdapter.setEnabled(true);
mBluetoothDeviceUpdater.onBluetoothStateChanged(BluetoothAdapter.STATE_ON);
verify(mDevicePreferenceCallback).onDeviceAdded(any(Preference.class));
}
@Test
public void onBluetoothStateChanged_bluetoothStateIsOff_removeAllDevicesFromPreference() {
mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference);
mBluetoothDeviceUpdater.onBluetoothStateChanged(BluetoothAdapter.STATE_OFF);
verify(mDevicePreferenceCallback).onDeviceRemoved(mPreference);
assertThat(mBluetoothDeviceUpdater.mPreferenceMap.containsKey(mBluetoothDevice)).isFalse();
}
}

View File

@@ -23,6 +23,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
@@ -32,6 +33,7 @@ import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowAudioManager;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -43,12 +45,13 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import java.util.ArrayList;
import java.util.Collection;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = {ShadowAudioManager.class})
@Config(shadows = {ShadowAudioManager.class, ShadowBluetoothAdapter.class})
public class ConnectedBluetoothDeviceUpdaterTest {
@Mock
private DashboardFragment mDashboardFragment;
@@ -67,12 +70,15 @@ public class ConnectedBluetoothDeviceUpdaterTest {
private ConnectedBluetoothDeviceUpdater mBluetoothDeviceUpdater;
private Collection<CachedBluetoothDevice> cachedDevices;
private ShadowAudioManager mShadowAudioManager;
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mShadowAudioManager = ShadowAudioManager.getShadow();
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
mShadowBluetoothAdapter.setEnabled(true);
mContext = RuntimeEnvironment.application;
doReturn(mContext).when(mDashboardFragment).getContext();
cachedDevices =

View File

@@ -0,0 +1,61 @@
/*
* 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.connecteddevice;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@RunWith(SettingsRobolectricTestRunner.class)
public class TopLevelConnectedDevicesPreferenceControllerTest {
private Context mContext;
private TopLevelConnectedDevicesPreferenceController mController;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mController = new TopLevelConnectedDevicesPreferenceController(mContext, "test_key");
}
@Test
@Config(shadows = ShadowAdvancedConnectedDeviceController.class)
public void getSummary_shouldCallAdvancedConnectedDeviceController() {
assertThat(mController.getSummary())
.isEqualTo(mContext.getText(R.string.settings_label_launcher));
}
@Implements(AdvancedConnectedDeviceController.class)
private static class ShadowAdvancedConnectedDeviceController {
@Implementation
public static int getConnectedDevicesSummaryResourceId(Context context) {
return R.string.settings_label_launcher;
}
}
}

View File

@@ -45,14 +45,14 @@ import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.dashboard.conditional.Condition;
import com.android.settings.homepage.conditional.Condition;
import com.android.settings.dashboard.suggestions.SuggestionAdapter;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settings.widget.RoundedHomepageIcon;
import com.android.settingslib.drawer.CategoryKey;
import com.android.settingslib.drawer.Tile;
import com.android.settingslib.drawer.TileUtils;
import com.android.settingslib.utils.IconCache;
import org.junit.Before;
@@ -95,7 +95,6 @@ public class DashboardAdapterTest {
mActivityInfo.packageName = "pkg";
mActivityInfo.name = "class";
mActivityInfo.metaData = new Bundle();
when(mFactory.dashboardFeatureProvider.shouldTintIcon()).thenReturn(true);
when(mContext.getSystemService(Context.WINDOW_SERVICE)).thenReturn(mWindowManager);
when(mContext.getResources()).thenReturn(mResources);
@@ -115,7 +114,7 @@ public class DashboardAdapterTest {
spy(new DashboardAdapter(mContext, null /* savedInstanceState */,
null /* conditions */, null /* suggestionControllerMixin */,
null /* lifecycle */));
final List<Suggestion> suggestions = makeSuggestionsV2("pkg1", "pkg2", "pkg3");
final List<Suggestion> suggestions = makeSuggestions("pkg1", "pkg2", "pkg3");
adapter.setSuggestions(suggestions);
final RecyclerView data = mock(RecyclerView.class);
@@ -147,7 +146,7 @@ public class DashboardAdapterTest {
spy(new DashboardAdapter(mContext, null /* savedInstanceState */,
null /* conditions */, null /* suggestionControllerMixin */,
null /* lifecycle */));
final List<Suggestion> suggestions = makeSuggestionsV2("pkg1");
final List<Suggestion> suggestions = makeSuggestions("pkg1");
adapter.setSuggestions(suggestions);
final DashboardData dashboardData = adapter.mDashboardData;
reset(adapter); // clear interactions tracking
@@ -164,7 +163,7 @@ public class DashboardAdapterTest {
spy(new DashboardAdapter(mContext, null /* savedInstanceState */,
null /* conditions */, null /* suggestionControllerMixin */,
null /* lifecycle */));
final List<Suggestion> suggestions = makeSuggestionsV2("pkg1");
final List<Suggestion> suggestions = makeSuggestions("pkg1");
adapter.setSuggestions(suggestions);
reset(adapter); // clear interactions tracking
@@ -178,7 +177,7 @@ public class DashboardAdapterTest {
public void onBindSuggestion_shouldSetSuggestionAdapterAndNoCrash() {
mDashboardAdapter = new DashboardAdapter(mContext, null /* savedInstanceState */,
null /* conditions */, null /* suggestionControllerMixin */, null /* lifecycle */);
final List<Suggestion> suggestions = makeSuggestionsV2("pkg1");
final List<Suggestion> suggestions = makeSuggestions("pkg1");
mDashboardAdapter.setSuggestions(suggestions);
@@ -243,55 +242,6 @@ public class DashboardAdapterTest {
.isInstanceOf(RoundedHomepageIcon.class);
}
@Test
public void onBindTile_externalTileWithBackgroundColorRawValue_shouldUpdateIcon() {
final Context context = spy(RuntimeEnvironment.application);
final View view = LayoutInflater.from(context).inflate(R.layout.dashboard_tile, null);
final DashboardAdapter.DashboardItemHolder holder =
new DashboardAdapter.DashboardItemHolder(view);
final Tile tile = spy(new Tile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE));
tile.getMetaData().putInt(DashboardAdapter.META_DATA_PREFERENCE_ICON_BACKGROUND_ARGB,
0xff0000);
doReturn(Icon.createWithResource(context, R.drawable.ic_settings))
.when(tile).getIcon(context);
final IconCache iconCache = new IconCache(context);
mDashboardAdapter = new DashboardAdapter(context, null /* savedInstanceState */,
null /* conditions */, null /* suggestionControllerMixin */, null /* lifecycle */);
ReflectionHelpers.setField(mDashboardAdapter, "mCache", iconCache);
doReturn("another.package").when(context).getPackageName();
mDashboardAdapter.onBindTile(holder, tile);
final RoundedHomepageIcon homepageIcon = (RoundedHomepageIcon) iconCache.getIcon(
tile.getIcon(context));
assertThat(homepageIcon.mBackgroundColor).isEqualTo(0xff0000);
}
@Test
public void onBindTile_externalTileWithBackgroundColorHint_shouldUpdateIcon() {
final Context context = spy(RuntimeEnvironment.application);
final View view = LayoutInflater.from(context).inflate(R.layout.dashboard_tile, null);
final DashboardAdapter.DashboardItemHolder holder =
new DashboardAdapter.DashboardItemHolder(view);
final Tile tile = spy(new Tile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE));
tile.getMetaData().putInt(TileUtils.META_DATA_PREFERENCE_ICON_BACKGROUND_HINT,
R.color.memory_critical);
doReturn(Icon.createWithResource(context, R.drawable.ic_settings))
.when(tile).getIcon(context);
final IconCache iconCache = new IconCache(context);
mDashboardAdapter = new DashboardAdapter(context, null /* savedInstanceState */,
null /* conditions */, null /* suggestionControllerMixin */, null /* lifecycle */);
ReflectionHelpers.setField(mDashboardAdapter, "mCache", iconCache);
doReturn("another.package").when(context).getPackageName();
mDashboardAdapter.onBindTile(holder, tile);
final RoundedHomepageIcon homepageIcon = (RoundedHomepageIcon) iconCache.getIcon(
tile.getIcon(context));
assertThat(homepageIcon.mBackgroundColor)
.isEqualTo(RuntimeEnvironment.application.getColor(R.color.memory_critical));
}
@Test
public void onBindTile_externalTile_usingRoundedHomepageIcon_shouldNotUpdateIcon() {
final Context context = RuntimeEnvironment.application;
@@ -315,7 +265,7 @@ public class DashboardAdapterTest {
any(RoundedHomepageIcon.class));
}
private List<Suggestion> makeSuggestionsV2(String... pkgNames) {
private List<Suggestion> makeSuggestions(String... pkgNames) {
final List<Suggestion> suggestions = new ArrayList<>();
for (String pkgName : pkgNames) {
final Suggestion suggestion = new Suggestion.Builder(pkgName)

View File

@@ -33,8 +33,8 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListUpdateCallback;
import com.android.settings.dashboard.conditional.AirplaneModeCondition;
import com.android.settings.dashboard.conditional.Condition;
import com.android.settings.homepage.conditional.AirplaneModeCondition;
import com.android.settings.homepage.conditional.Condition;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.drawer.CategoryKey;
import com.android.settingslib.drawer.DashboardCategory;

View File

@@ -49,7 +49,7 @@ import android.os.UserManager;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.Preference;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.testutils.FakeFeatureFactory;
@@ -59,7 +59,6 @@ import com.android.settings.testutils.shadow.ShadowTileUtils;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.drawer.CategoryKey;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.Tile;
import com.android.settingslib.drawer.TileUtils;
@@ -88,19 +87,19 @@ public class DashboardFeatureProviderImplTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private UserManager mUserManager;
@Mock
private CategoryManager mCategoryManager;
@Mock
private PackageManager mPackageManager;
private FakeFeatureFactory mFeatureFactory;
private Context mContext;
private ActivityInfo mActivityInfo;
private DashboardFeatureProviderImpl mImpl;
private boolean mForceRoundedIcon;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mForceRoundedIcon = false;
mActivityInfo = new ActivityInfo();
mActivityInfo.packageName = "pkg";
mActivityInfo.name = "class";
@@ -127,7 +126,7 @@ public class DashboardFeatureProviderImplTest {
doReturn(Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565)))
.when(tile).getIcon(any(Context.class));
mActivityInfo.metaData.putString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS, "HI");
mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.SETTINGS_GESTURES,
mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES,
preference, tile, "123", Preference.DEFAULT_ORDER);
assertThat(preference.getTitle()).isEqualTo(tile.title);
@@ -144,7 +143,7 @@ public class DashboardFeatureProviderImplTest {
mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10);
final Tile tile = new Tile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.SETTINGS_GESTURES,
mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES,
preference, tile, "123", Preference.DEFAULT_ORDER);
assertThat(preference.getFragment()).isNull();
@@ -163,7 +162,7 @@ public class DashboardFeatureProviderImplTest {
when(mActivity.getApplicationContext().getSystemService(Context.USER_SERVICE))
.thenReturn(mUserManager);
mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.SETTINGS_GESTURES,
mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES,
preference, tile, "123", Preference.DEFAULT_ORDER);
preference.getOnPreferenceClickListener().onPreferenceClick(null);
@@ -180,14 +179,14 @@ public class DashboardFeatureProviderImplTest {
when(mActivity.getSystemService(Context.USER_SERVICE))
.thenReturn(mUserManager);
mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.SETTINGS_GESTURES,
mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES,
preference, tile, "123", Preference.DEFAULT_ORDER);
preference.getOnPreferenceClickListener().onPreferenceClick(null);
verify(mFeatureFactory.metricsFeatureProvider).logDashboardStartIntent(
any(Context.class),
any(Intent.class),
eq(MetricsProto.MetricsEvent.SETTINGS_GESTURES));
eq(MetricsEvent.SETTINGS_GESTURES));
verify(mActivity)
.startActivityForResultAsUser(any(Intent.class), anyInt(), any(UserHandle.class));
}
@@ -205,7 +204,7 @@ public class DashboardFeatureProviderImplTest {
when(mActivity.getApplicationContext().getPackageName())
.thenReturn(RuntimeEnvironment.application.getPackageName());
mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.SETTINGS_GESTURES,
mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES,
preference, tile, "123", Preference.DEFAULT_ORDER);
preference.getOnPreferenceClickListener().onPreferenceClick(null);
verify(mFeatureFactory.metricsFeatureProvider).logDashboardStartIntent(
@@ -219,7 +218,7 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_nullPreference_shouldIgnore() {
final Tile tile = mock(Tile.class);
mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN,
mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN,
null, tile, "123", Preference.DEFAULT_ORDER);
verifyZeroInteractions(tile);
@@ -229,7 +228,7 @@ public class DashboardFeatureProviderImplTest {
public void bindPreference_withNullKeyNullPriority_shouldGenerateKeyAndPriority() {
final Preference preference = new Preference(RuntimeEnvironment.application);
final Tile tile = new Tile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN,
mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN,
preference, tile, null /*key */, Preference.DEFAULT_ORDER);
assertThat(preference.getKey()).isNotNull();
@@ -240,7 +239,7 @@ public class DashboardFeatureProviderImplTest {
public void bindPreference_noSummary_shouldSetSummaryToPlaceholder() {
final Preference preference = new Preference(RuntimeEnvironment.application);
final Tile tile = new Tile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN,
mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN,
preference, tile, null /*key */, Preference.DEFAULT_ORDER);
assertThat(preference.getSummary())
@@ -252,7 +251,7 @@ public class DashboardFeatureProviderImplTest {
final Preference preference = new Preference(RuntimeEnvironment.application);
final Tile tile = new Tile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
tile.summary = "test";
mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN,
mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN,
preference, tile, null /*key */, Preference.DEFAULT_ORDER);
assertThat(preference.getSummary()).isEqualTo(tile.summary);
@@ -266,7 +265,7 @@ public class DashboardFeatureProviderImplTest {
mActivityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI,
"content://com.android.settings/tile_summary");
mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN,
mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN,
preference, tile, null /*key */, Preference.DEFAULT_ORDER);
assertThat(preference.getSummary()).isEqualTo(ShadowTileUtils.MOCK_SUMMARY);
@@ -277,7 +276,7 @@ public class DashboardFeatureProviderImplTest {
final Preference preference = new Preference(RuntimeEnvironment.application);
mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
final Tile tile = new Tile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN,
mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN,
preference, tile, null /* key */, Preference.DEFAULT_ORDER);
assertThat(preference.getKey()).isEqualTo(tile.getKey(mContext));
@@ -292,7 +291,7 @@ public class DashboardFeatureProviderImplTest {
mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
mActivityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_ICON_URI,
"content://com.android.settings/tile_icon");
mImpl.bindIcon(preference, tile);
mImpl.bindIcon(preference, tile, false /* forceRoundedIcon */);
assertThat(preference.getIcon()).isNotNull();
}
@@ -304,7 +303,7 @@ public class DashboardFeatureProviderImplTest {
mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10);
final Tile tile = new Tile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN,
mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN,
preference, tile, "123", baseOrder);
assertThat(preference.getOrder()).isEqualTo(tile.getOrder() + baseOrder);
@@ -317,7 +316,7 @@ public class DashboardFeatureProviderImplTest {
mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10);
final Tile tile = new Tile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, testOrder);
mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN,
mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN,
preference, tile, "123", Preference.DEFAULT_ORDER);
assertThat(preference.getOrder()).isEqualTo(testOrder);
@@ -329,7 +328,7 @@ public class DashboardFeatureProviderImplTest {
final Tile tile = new Tile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mActivityInfo.metaData.putString(META_DATA_KEY_ORDER, "hello");
mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN,
mImpl.bindPreferenceToTile(mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN,
preference, tile, "123", Preference.DEFAULT_ORDER);
assertThat(preference.getOrder()).isEqualTo(Preference.DEFAULT_ORDER);
@@ -343,7 +342,7 @@ public class DashboardFeatureProviderImplTest {
mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
mActivityInfo.metaData.putString("com.android.settings.intent.action", "TestAction");
tile.userHandle = null;
mImpl.bindPreferenceToTile(activity, MetricsProto.MetricsEvent.SETTINGS_GESTURES,
mImpl.bindPreferenceToTile(activity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES,
preference, tile, "123", Preference.DEFAULT_ORDER);
preference.performClick();
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
@@ -352,7 +351,7 @@ public class DashboardFeatureProviderImplTest {
assertThat(launchIntent.getAction())
.isEqualTo("TestAction");
assertThat(launchIntent.getIntExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY, 0))
.isEqualTo(MetricsProto.MetricsEvent.SETTINGS_GESTURES);
.isEqualTo(MetricsEvent.SETTINGS_GESTURES);
}
@Test
@@ -367,7 +366,7 @@ public class DashboardFeatureProviderImplTest {
mActivityInfo.metaData.putString("com.android.settings.intent.action", "TestAction");
tile.userHandle = null;
mImpl.bindPreferenceToTile(activity, MetricsProto.MetricsEvent.SETTINGS_GESTURES,
mImpl.bindPreferenceToTile(activity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES,
preference, tile, "123", Preference.DEFAULT_ORDER);
preference.performClick();
@@ -377,63 +376,11 @@ public class DashboardFeatureProviderImplTest {
assertThat(launchIntent).isNull();
}
@Test
public void getPreferences_noCategory_shouldReturnNull() {
mImpl = new DashboardFeatureProviderImpl(mActivity);
ReflectionHelpers.setField(mImpl, "mCategoryManager", mCategoryManager);
when(mCategoryManager.getTilesByCategory(mActivity, CategoryKey.CATEGORY_HOMEPAGE))
.thenReturn(null);
assertThat(mImpl.getPreferencesForCategory(null, null,
MetricsProto.MetricsEvent.SETTINGS_GESTURES, CategoryKey.CATEGORY_HOMEPAGE))
.isNull();
}
@Test
public void getPreferences_noTileForCategory_shouldReturnNull() {
mImpl = new DashboardFeatureProviderImpl(mActivity);
ReflectionHelpers.setField(mImpl, "mCategoryManager", mCategoryManager);
when(mCategoryManager.getTilesByCategory(mActivity, CategoryKey.CATEGORY_HOMEPAGE))
.thenReturn(new DashboardCategory(CategoryKey.CATEGORY_HOMEPAGE));
assertThat(mImpl.getPreferencesForCategory(null, null,
MetricsProto.MetricsEvent.SETTINGS_GESTURES, CategoryKey.CATEGORY_HOMEPAGE))
.isNull();
}
@Test
public void getPreferences_hasTileForCategory_shouldReturnPrefList() {
mImpl = new DashboardFeatureProviderImpl(mActivity);
ReflectionHelpers.setField(mImpl, "mCategoryManager", mCategoryManager);
final DashboardCategory category = new DashboardCategory(CategoryKey.CATEGORY_HOMEPAGE);
category.addTile(new Tile(mActivityInfo, category.key));
when(mCategoryManager
.getTilesByCategory(any(Context.class), eq(CategoryKey.CATEGORY_HOMEPAGE)))
.thenReturn(category);
assertThat(mImpl.getPreferencesForCategory(mActivity,
ShadowApplication.getInstance().getApplicationContext(),
MetricsProto.MetricsEvent.SETTINGS_GESTURES,
CategoryKey.CATEGORY_HOMEPAGE).isEmpty())
.isFalse();
}
@Test
public void testGetExtraIntentAction_shouldReturnNull() {
assertThat(mImpl.getExtraIntentAction()).isNull();
}
@Test
public void testShouldTintIcon_enabledInResources_shouldBeTrue() {
assertThat(mImpl.shouldTintIcon()).isTrue();
}
@Test
@Config(qualifiers = "mcc999")
public void testShouldTintIcon_disabledInResources_shouldBeFalse() {
assertThat(mImpl.shouldTintIcon()).isFalse();
}
@Test
public void openTileIntent_profileSelectionDialog_shouldShow() {
final Tile tile = new Tile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);

View File

@@ -0,0 +1,33 @@
/*
* 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.dashboard;
import static com.google.common.truth.Truth.assertThat;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(SettingsRobolectricTestRunner.class)
public class DashboardFragmentRegistryTest {
@Test
public void pageAndKeyShouldHave1to1Mapping() {
assertThat(DashboardFragmentRegistry.CATEGORY_KEY_TO_PARENT_MAP.size())
.isEqualTo(DashboardFragmentRegistry.PARENT_TO_CATEGORY_KEY_MAP.size());
}
}

View File

@@ -30,8 +30,8 @@ import static org.mockito.Mockito.when;
import android.app.Activity;
import android.content.Context;
import com.android.settings.dashboard.conditional.ConditionManager;
import com.android.settings.dashboard.conditional.FocusRecyclerView;
import com.android.settings.homepage.conditional.ConditionManager;
import com.android.settings.homepage.conditional.FocusRecyclerView;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.drawer.CategoryKey;

View File

@@ -355,7 +355,7 @@ public class DataUsageSummaryPreferenceControllerTest {
mActivity, null, null, null);
final SubscriptionInfo subInfo = new SubscriptionInfo(0, "123456", 0, "name", "carrier",
0, 0, "number", 0, null, "123", "456", "ZX");
0, 0, "number", 0, null, "123", "456", "ZX", false, null, null);
when(mSubscriptionManager.getDefaultDataSubscriptionInfo()).thenReturn(subInfo);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}

View File

@@ -17,7 +17,6 @@
package com.android.settings.deviceinfo;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -25,14 +24,9 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.app.usage.StorageStatsManager;
import android.content.Intent;
import android.icu.text.NumberFormat;
import android.os.storage.VolumeInfo;
import android.text.format.Formatter;
import com.android.settings.R;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
@@ -41,8 +35,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.List;
@@ -65,34 +57,6 @@ public class StorageSettingsTest {
when(mStorageManagerVolumeProvider.getVolumes()).thenReturn(mVolumes);
}
@Test
public void updateSummary_shouldDisplayUsedPercentAndFreeSpace() throws Exception {
final SummaryLoader loader = mock(SummaryLoader.class);
final SummaryLoader.SummaryProvider provider =
StorageSettings.SUMMARY_PROVIDER_FACTORY.createSummaryProvider(mActivity, loader);
final VolumeInfo volumeInfo = mVolumes.get(0);
when(volumeInfo.isMountedReadable()).thenReturn(true);
when(volumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
when(mStorageManagerVolumeProvider
.getTotalBytes(nullable(StorageStatsManager.class), nullable(VolumeInfo.class)))
.thenReturn(500L);
when(mStorageManagerVolumeProvider
.getFreeBytes(nullable(StorageStatsManager.class), nullable(VolumeInfo.class)))
.thenReturn(0L);
ReflectionHelpers
.setField(provider, "mStorageManagerVolumeProvider", mStorageManagerVolumeProvider);
ReflectionHelpers.setField(provider, "mContext", RuntimeEnvironment.application);
provider.setListening(true);
final String percentage = NumberFormat.getPercentInstance().format(1);
final String freeSpace = Formatter.formatFileSize(RuntimeEnvironment.application, 0);
verify(loader).setSummary(provider,
RuntimeEnvironment.application.getString(
R.string.storage_summary, percentage, freeSpace));
}
@Test
public void handlePublicVolumeClick_startsANonNullActivityWhenVolumeHasNoBrowse() {
VolumeInfo volumeInfo = mock(VolumeInfo.class, RETURNS_DEEP_STUBS);

View File

@@ -0,0 +1,90 @@
/*
* 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.deviceinfo;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.app.usage.StorageStatsManager;
import android.content.Context;
import android.icu.text.NumberFormat;
import android.os.storage.VolumeInfo;
import android.text.format.Formatter;
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
public class TopLevelStoragePreferenceControllerTest {
@Mock
private StorageManagerVolumeProvider mStorageManagerVolumeProvider;
private Context mContext;
private TopLevelStoragePreferenceController mController;
private List<VolumeInfo> mVolumes;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mVolumes = new ArrayList<>();
mVolumes.add(mock(VolumeInfo.class, RETURNS_DEEP_STUBS));
when(mStorageManagerVolumeProvider.getVolumes()).thenReturn(mVolumes);
mController = new TopLevelStoragePreferenceController(mContext, "test_key");
}
@Test
public void updateSummary_shouldDisplayUsedPercentAndFreeSpace() throws Exception {
final VolumeInfo volumeInfo = mVolumes.get(0);
when(volumeInfo.isMountedReadable()).thenReturn(true);
when(volumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
when(mStorageManagerVolumeProvider
.getTotalBytes(nullable(StorageStatsManager.class), nullable(VolumeInfo.class)))
.thenReturn(500L);
when(mStorageManagerVolumeProvider
.getFreeBytes(nullable(StorageStatsManager.class), nullable(VolumeInfo.class)))
.thenReturn(0L);
ReflectionHelpers.setField(mController,
"mStorageManagerVolumeProvider", mStorageManagerVolumeProvider);
final String percentage = NumberFormat.getPercentInstance().format(1);
final String freeSpace = Formatter.formatFileSize(RuntimeEnvironment.application, 0);
assertThat(mController.getSummary()).isEqualTo(
RuntimeEnvironment.application.getString(
R.string.storage_summary, percentage, freeSpace));
}
}

View File

@@ -56,7 +56,6 @@ public class BatterySaverControllerTest {
mBatterySaverController = spy(new BatterySaverController(mContext));
ReflectionHelpers.setField(mBatterySaverController, "mPowerManager", mPowerManager);
ReflectionHelpers.setField(mBatterySaverController, "mBatterySaverPref", mBatterySaverPref);
doNothing().when(mBatterySaverController).refreshConditionManager();
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);

View File

@@ -16,7 +16,9 @@
package com.android.settings.fuelgauge;
import static com.android.settings.fuelgauge.PowerUsageSummary.MENU_ADVANCED_BATTERY;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
@@ -40,6 +42,8 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import androidx.loader.app.LoaderManager;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R;
@@ -50,7 +54,6 @@ import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.XmlTestUtils;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settingslib.core.AbstractPreferenceController;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -69,8 +72,6 @@ import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.List;
import androidx.loader.app.LoaderManager;
// TODO: Improve this test class so that it starts up the real activity and fragment.
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = {
@@ -343,18 +344,6 @@ public class PowerUsageSummaryTest {
verify(mFragment).restartBatteryTipLoader();
}
@Test
public void getDashboardLabel_returnsCorrectLabel() {
BatteryInfo info = new BatteryInfo();
info.batteryPercentString = "3%";
assertThat(PowerUsageSummary.getDashboardLabel(mRealContext, info))
.isEqualTo(info.batteryPercentString);
info.remainingLabel = "Phone will shut down soon";
assertThat(PowerUsageSummary.getDashboardLabel(mRealContext, info))
.isEqualTo("3% - Phone will shut down soon");
}
public static class TestFragment extends PowerUsageSummary {
private Context mContext;

View File

@@ -0,0 +1,53 @@
/*
* 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 static com.android.settings.fuelgauge.TopLevelBatteryPreferenceController.getDashboardLabel;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
public class TopLevelBatteryPreferenceControllerTest {
private Context mContext;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
}
@Test
public void getDashboardLabel_returnsCorrectLabel() {
BatteryInfo info = new BatteryInfo();
info.batteryPercentString = "3%";
assertThat(getDashboardLabel(mContext, info))
.isEqualTo(info.batteryPercentString);
info.remainingLabel = "Phone will shut down soon";
assertThat(getDashboardLabel(mContext, info))
.isEqualTo("3% - Phone will shut down soon");
}
}

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.homepage;
import static com.google.common.truth.Truth.assertThat;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
public class CardContentProviderTest {
private Context mContext;
private CardContentProvider mProvider;
private Uri mUri;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mProvider = Robolectric.setupContentProvider(CardContentProvider.class);
mUri = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(CardContentProvider.CARD_AUTHORITY)
.path(CardDatabaseHelper.CARD_TABLE)
.build();
}
@After
public void cleanUp() {
CardDatabaseHelper.getInstance(mContext).close();
CardDatabaseHelper.sCardDatabaseHelper = null;
}
@Test
public void cardData_insert() {
final int cnt_before_instert = getRowCount();
mContext.getContentResolver().insert(mUri, insertOneRow());
final int cnt_after_instert = getRowCount();
assertThat(cnt_after_instert - cnt_before_instert).isEqualTo(1);
}
@Test
public void cardData_query() {
mContext.getContentResolver().insert(mUri, insertOneRow());
final int count = getRowCount();
assertThat(count).isGreaterThan(0);
}
@Test
public void cardData_delete() {
final ContentResolver contentResolver = mContext.getContentResolver();
contentResolver.insert(mUri, insertOneRow());
final int del_count = contentResolver.delete(mUri, null, null);
assertThat(del_count).isGreaterThan(0);
}
@Test
public void cardData_update() {
final ContentResolver contentResolver = mContext.getContentResolver();
contentResolver.insert(mUri, insertOneRow());
final double updatingScore= 0.87;
final ContentValues values = new ContentValues();
values.put(CardDatabaseHelper.CardColumns.SCORE, updatingScore);
final String strWhere = CardDatabaseHelper.CardColumns.NAME + "=?";
final String[] selectionArgs = {"auto_rotate"};
final int update_count = contentResolver.update(mUri, values, strWhere, selectionArgs);
assertThat(update_count).isGreaterThan(0);
final String[] columns = {CardDatabaseHelper.CardColumns.SCORE};
final Cursor cr = contentResolver.query(mUri, columns, strWhere, selectionArgs, null);
cr.moveToFirst();
final double qryScore = cr.getDouble(0);
cr.close();
assertThat(qryScore).isEqualTo(updatingScore);
}
@Test(expected = UnsupportedOperationException.class)
public void getType_shouldCrash() {
mProvider.getType(null);
}
@Test(expected = IllegalArgumentException.class)
public void invalid_Uri_shouldCrash() {
final Uri invalid_Uri = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(CardContentProvider.CARD_AUTHORITY)
.path("Invalid_table")
.build();
mProvider.getTableFromMatch(invalid_Uri);
}
private ContentValues insertOneRow() {
final ContentValues values = new ContentValues();
values.put(CardDatabaseHelper.CardColumns.NAME, "auto_rotate");
values.put(CardDatabaseHelper.CardColumns.TYPE, 0);
values.put(CardDatabaseHelper.CardColumns.SCORE, 0.9);
values.put(CardDatabaseHelper.CardColumns.SLICE_URI,
"content://com.android.settings.slices/action/auto_rotate");
values.put(CardDatabaseHelper.CardColumns.CATEGORY, 2);
values.put(CardDatabaseHelper.CardColumns.PACKAGE_NAME, "com.android.settings");
values.put(CardDatabaseHelper.CardColumns.APP_VERSION, "1.0.0");
return values;
}
private int getRowCount() {
final ContentResolver contentResolver = mContext.getContentResolver();
final Cursor cr = contentResolver.query(mUri, null, null, null);
final int count = cr.getCount();
cr.close();
return count;
}
}

View File

@@ -0,0 +1,83 @@
/*
* 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.homepage;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
public class CardDatabaseHelperTest {
private Context mContext;
private CardDatabaseHelper mCardDatabaseHelper;
private SQLiteDatabase mDatabase;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mCardDatabaseHelper = CardDatabaseHelper.getInstance(mContext);
mDatabase = mCardDatabaseHelper.getWritableDatabase();
}
@After
public void cleanUp() {
CardDatabaseHelper.getInstance(mContext).close();
CardDatabaseHelper.sCardDatabaseHelper = null;
}
@Test
public void testDatabaseSchema() {
final Cursor cursor = mDatabase.rawQuery("SELECT * FROM " + CardDatabaseHelper.CARD_TABLE,
null);
final String[] columnNames = cursor.getColumnNames();
final String[] expectedNames = {
CardDatabaseHelper.CardColumns.NAME,
CardDatabaseHelper.CardColumns.TYPE,
CardDatabaseHelper.CardColumns.SCORE,
CardDatabaseHelper.CardColumns.SLICE_URI,
CardDatabaseHelper.CardColumns.CATEGORY,
CardDatabaseHelper.CardColumns.AVAILABILITY_URI,
CardDatabaseHelper.CardColumns.LOCALIZED_TO_LOCALE,
CardDatabaseHelper.CardColumns.PACKAGE_NAME,
CardDatabaseHelper.CardColumns.APP_VERSION,
CardDatabaseHelper.CardColumns.TITLE_RES_NAME,
CardDatabaseHelper.CardColumns.TITLE_TEXT,
CardDatabaseHelper.CardColumns.SUMMARY_RES_NAME,
CardDatabaseHelper.CardColumns.SUMMARY_TEXT,
CardDatabaseHelper.CardColumns.ICON_RES_NAME,
CardDatabaseHelper.CardColumns.ICON_RES_ID,
CardDatabaseHelper.CardColumns.CARD_ACTION,
CardDatabaseHelper.CardColumns.EXPIRE_TIME_MS,
};
assertThat(columnNames).isEqualTo(expectedNames);
cursor.close();
}
}

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