Adds contextual cards for screen attention in Settings Homepage
Bug: 128527964 Test: atest ContextualAdaptiveSleepSliceTest, maually verified. Change-Id: Ifaea7d8d4391e91cf6cbde38a2506728f55913d8
This commit is contained in:
31
res/drawable/ic_settings_adaptive_sleep.xml
Normal file
31
res/drawable/ic_settings_adaptive_sleep.xml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<!--
|
||||||
|
Copyright (C) 2019 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M10.67,21H7v-1h3.13c-0.27-0.63-0.46-1.3-0.56-2H7V6h10v3.5c0.69,0,1.36,0.1,2,0.28V3 c0-1.1-0.9-1.99-2-1.99L7,1C5.9,1,5,1.9,5,3v18c0,1.1,0.9,2,2,2h5.52C11.79,22.45,11.16,21.77,10.67,21z M7,3h10v1H7V3z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M17,12.5c2.48,0,4.5,2.02,4.5,4.5s-2.02,4.5-4.5,4.5s-4.5-2.02-4.5-4.5S14.52,12.5,17,12.5 M17,11 c-3.31,0-6,2.69-6,6s2.69,6,6,6c3.31,0,6-2.69,6-6S20.31,11,17,11L17,11z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M17,14v3l-2.12,2.12C15.42,19.66,16.17,20,17,20c1.66,0,3-1.34,3-3S18.66,14,17,14z" />
|
||||||
|
</vector>
|
@@ -2833,7 +2833,7 @@
|
|||||||
<!-- Setting option summary when adaptive sleep is off [CHAR LIMIT=NONE] -->
|
<!-- Setting option summary when adaptive sleep is off [CHAR LIMIT=NONE] -->
|
||||||
<string name="adaptive_sleep_summary_off">Off</string>
|
<string name="adaptive_sleep_summary_off">Off</string>
|
||||||
<!-- Description about the feature adaptive sleep [CHAR LIMIT=NONE]-->
|
<!-- Description about the feature adaptive sleep [CHAR LIMIT=NONE]-->
|
||||||
<string name="adaptive_sleep_description">Prevents your screen from turning off if you’re looking at it.</string>
|
<string name="adaptive_sleep_description">Keep screen on when viewing it</string>
|
||||||
<!-- Description feature's privacy sensitive details to make sure users understand what feature users, what it saves/sends etc [CHAR LIMIT=NONE]-->
|
<!-- Description feature's privacy sensitive details to make sure users understand what feature users, what it saves/sends etc [CHAR LIMIT=NONE]-->
|
||||||
<string name="adaptive_sleep_privacy">Screen attention uses the front camera to see if someone is looking at the screen. It works on device, and images are never stored or sent to Google.</string>
|
<string name="adaptive_sleep_privacy">Screen attention uses the front camera to see if someone is looking at the screen. It works on device, and images are never stored or sent to Google.</string>
|
||||||
|
|
||||||
|
@@ -25,9 +25,9 @@ import com.android.settings.core.TogglePreferenceController;
|
|||||||
|
|
||||||
|
|
||||||
public class AdaptiveSleepPreferenceController extends TogglePreferenceController {
|
public class AdaptiveSleepPreferenceController extends TogglePreferenceController {
|
||||||
|
public static final String PREF_NAME = "adaptive_sleep";
|
||||||
private final String SYSTEM_KEY = ADAPTIVE_SLEEP;
|
private static final String SYSTEM_KEY = ADAPTIVE_SLEEP;
|
||||||
private final int DEFAULT_VALUE = 0;
|
private static final int DEFAULT_VALUE = 0;
|
||||||
|
|
||||||
final boolean hasSufficientPermissions;
|
final boolean hasSufficientPermissions;
|
||||||
|
|
||||||
@@ -35,9 +35,7 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle
|
|||||||
super(context, key);
|
super(context, key);
|
||||||
|
|
||||||
final PackageManager packageManager = mContext.getPackageManager();
|
final PackageManager packageManager = mContext.getPackageManager();
|
||||||
final String attentionPackage = packageManager.getAttentionServicePackageName();
|
hasSufficientPermissions = hasSufficientPermission(packageManager);
|
||||||
hasSufficientPermissions = attentionPackage != null && packageManager.checkPermission(
|
|
||||||
Manifest.permission.CAMERA, attentionPackage) == PackageManager.PERMISSION_GRANTED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -46,7 +44,6 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle
|
|||||||
SYSTEM_KEY, DEFAULT_VALUE) != DEFAULT_VALUE;
|
SYSTEM_KEY, DEFAULT_VALUE) != DEFAULT_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setChecked(boolean isChecked) {
|
public boolean setChecked(boolean isChecked) {
|
||||||
Settings.System.putInt(mContext.getContentResolver(), SYSTEM_KEY,
|
Settings.System.putInt(mContext.getContentResolver(), SYSTEM_KEY,
|
||||||
@@ -57,10 +54,7 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle
|
|||||||
@Override
|
@Override
|
||||||
@AvailabilityStatus
|
@AvailabilityStatus
|
||||||
public int getAvailabilityStatus() {
|
public int getAvailabilityStatus() {
|
||||||
return mContext.getResources().getBoolean(
|
return isControllerAvailable(mContext);
|
||||||
com.android.internal.R.bool.config_adaptive_sleep_available)
|
|
||||||
? AVAILABLE_UNSEARCHABLE
|
|
||||||
: UNSUPPORTED_ON_DEVICE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -69,4 +63,17 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle
|
|||||||
? R.string.adaptive_sleep_summary_on
|
? R.string.adaptive_sleep_summary_on
|
||||||
: R.string.adaptive_sleep_summary_off);
|
: R.string.adaptive_sleep_summary_off);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int isControllerAvailable(Context context) {
|
||||||
|
return context.getResources().getBoolean(
|
||||||
|
com.android.internal.R.bool.config_adaptive_sleep_available)
|
||||||
|
? AVAILABLE_UNSEARCHABLE
|
||||||
|
: UNSUPPORTED_ON_DEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasSufficientPermission(PackageManager packageManager) {
|
||||||
|
final String attentionPackage = packageManager.getAttentionServicePackageName();
|
||||||
|
return attentionPackage != null && packageManager.checkPermission(
|
||||||
|
Manifest.permission.CAMERA, attentionPackage) == PackageManager.PERMISSION_GRANTED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,10 +16,15 @@
|
|||||||
|
|
||||||
package com.android.settings.display;
|
package com.android.settings.display;
|
||||||
|
|
||||||
|
import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.PREF;
|
||||||
|
import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.PREF_KEY_INTERACTED;
|
||||||
|
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.SearchIndexableResource;
|
import android.provider.SearchIndexableResource;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
@@ -40,8 +45,15 @@ public class AdaptiveSleepSettings extends DashboardFragment {
|
|||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
final FooterPreference footerPreference =
|
final FooterPreference footerPreference =
|
||||||
mFooterPreferenceMixin.createFooterPreference();
|
mFooterPreferenceMixin.createFooterPreference();
|
||||||
|
final Context context = getContext();
|
||||||
|
|
||||||
footerPreference.setIcon(R.drawable.ic_privacy_shield_24dp);
|
footerPreference.setIcon(R.drawable.ic_privacy_shield_24dp);
|
||||||
footerPreference.setTitle(R.string.adaptive_sleep_privacy);
|
footerPreference.setTitle(R.string.adaptive_sleep_privacy);
|
||||||
|
|
||||||
|
context.getSharedPreferences(PREF, Context.MODE_PRIVATE)
|
||||||
|
.edit()
|
||||||
|
.putBoolean(PREF_KEY_INTERACTED, true)
|
||||||
|
.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -64,12 +64,21 @@ public class SettingsContextualCardProvider extends ContextualCardProvider {
|
|||||||
.setCardName(contextualNotificationChannelSliceUri)
|
.setCardName(contextualNotificationChannelSliceUri)
|
||||||
.setCardCategory(ContextualCard.Category.POSSIBLE)
|
.setCardCategory(ContextualCard.Category.POSSIBLE)
|
||||||
.build();
|
.build();
|
||||||
|
final String contextualAdaptiveSleepSliceUri =
|
||||||
|
CustomSliceRegistry.CONTEXTUAL_ADAPTIVE_SLEEP_URI.toString();
|
||||||
|
final ContextualCard contextualAdaptiveSleepCard =
|
||||||
|
ContextualCard.newBuilder()
|
||||||
|
.setSliceUri(contextualAdaptiveSleepSliceUri)
|
||||||
|
.setCardName(contextualAdaptiveSleepSliceUri)
|
||||||
|
.setCardCategory(ContextualCard.Category.DEFAULT)
|
||||||
|
.build();
|
||||||
final ContextualCardList cards = ContextualCardList.newBuilder()
|
final ContextualCardList cards = ContextualCardList.newBuilder()
|
||||||
.addCard(wifiCard)
|
.addCard(wifiCard)
|
||||||
.addCard(connectedDeviceCard)
|
.addCard(connectedDeviceCard)
|
||||||
.addCard(lowStorageCard)
|
.addCard(lowStorageCard)
|
||||||
.addCard(batteryFixCard)
|
.addCard(batteryFixCard)
|
||||||
.addCard(notificationChannelCard)
|
.addCard(notificationChannelCard)
|
||||||
|
.addCard(contextualAdaptiveSleepCard)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
return cards;
|
return cards;
|
||||||
|
@@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.homepage.contextualcards.slices;
|
||||||
|
|
||||||
|
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
|
||||||
|
import static com.android.settings.display.AdaptiveSleepPreferenceController.PREF_NAME;
|
||||||
|
import static com.android.settings.display.AdaptiveSleepPreferenceController.isControllerAvailable;
|
||||||
|
import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_ADAPTIVE_SLEEP_URI;
|
||||||
|
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.app.settings.SettingsEnums;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import androidx.core.graphics.drawable.IconCompat;
|
||||||
|
import androidx.slice.Slice;
|
||||||
|
import androidx.slice.builders.ListBuilder;
|
||||||
|
import androidx.slice.builders.SliceAction;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.SubSettings;
|
||||||
|
import com.android.settings.display.AdaptiveSleepSettings;
|
||||||
|
import com.android.settings.slices.CustomSliceable;
|
||||||
|
import com.android.settings.slices.SliceBuilderUtils;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class ContextualAdaptiveSleepSlice implements CustomSliceable {
|
||||||
|
private static final String TAG = "ContextualAdaptiveSleepSlice";
|
||||||
|
private static final long DEFAULT_SETUP_TIME = 0;
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static final long DEFERRED_TIME_DAYS = TimeUnit.DAYS.toMillis(14);
|
||||||
|
@VisibleForTesting
|
||||||
|
static final String PREF_KEY_SETUP_TIME = "adaptive_sleep_setup_time";
|
||||||
|
|
||||||
|
public static final String PREF_KEY_INTERACTED = "adaptive_sleep_interacted";
|
||||||
|
public static final String PREF = "adaptive_sleep_slice";
|
||||||
|
|
||||||
|
public ContextualAdaptiveSleepSlice(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Slice getSlice() {
|
||||||
|
final long setupTime = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE).getLong(
|
||||||
|
PREF_KEY_SETUP_TIME, DEFAULT_SETUP_TIME);
|
||||||
|
if (setupTime == DEFAULT_SETUP_TIME) {
|
||||||
|
// Set the first setup time.
|
||||||
|
mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE)
|
||||||
|
.edit()
|
||||||
|
.putLong(PREF_KEY_SETUP_TIME, System.currentTimeMillis())
|
||||||
|
.apply();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the contextual card only if all the following 3 conditions hold:
|
||||||
|
// 1. The Screen Attention is enabled in Settings.
|
||||||
|
// 2. The device is not recently set up.
|
||||||
|
// 3. Current user hasn't opened Screen Attention's settings page before.
|
||||||
|
if (isSettingsAvailable() && !isUserInteracted() && !isRecentlySetup()) {
|
||||||
|
final IconCompat icon = IconCompat.createWithResource(mContext,
|
||||||
|
R.drawable.ic_settings_adaptive_sleep);
|
||||||
|
final CharSequence title = mContext.getText(R.string.adaptive_sleep_title);
|
||||||
|
final CharSequence subtitle = mContext.getText(R.string.adaptive_sleep_description);
|
||||||
|
|
||||||
|
final SliceAction pAction = SliceAction.createDeeplink(getPrimaryAction(),
|
||||||
|
icon,
|
||||||
|
ListBuilder.ICON_IMAGE,
|
||||||
|
title);
|
||||||
|
final ListBuilder listBuilder = new ListBuilder(mContext,
|
||||||
|
CONTEXTUAL_ADAPTIVE_SLEEP_URI,
|
||||||
|
ListBuilder.INFINITY)
|
||||||
|
.addRow(new ListBuilder.RowBuilder()
|
||||||
|
.setTitleItem(icon, ListBuilder.ICON_IMAGE)
|
||||||
|
.setTitle(title)
|
||||||
|
.setSubtitle(subtitle)
|
||||||
|
.setPrimaryAction(pAction));
|
||||||
|
return listBuilder.build();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getUri() {
|
||||||
|
return CONTEXTUAL_ADAPTIVE_SLEEP_URI;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Intent getIntent() {
|
||||||
|
final CharSequence screenTitle = mContext.getText(R.string.adaptive_sleep_title);
|
||||||
|
final Uri contentUri = new Uri.Builder().appendPath(PREF_NAME).build();
|
||||||
|
return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
|
||||||
|
AdaptiveSleepSettings.class.getName(), PREF_NAME, screenTitle.toString(),
|
||||||
|
SettingsEnums.SLICE).setClassName(mContext.getPackageName(),
|
||||||
|
SubSettings.class.getName()).setData(contentUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PendingIntent getPrimaryAction() {
|
||||||
|
final Intent intent = getIntent();
|
||||||
|
return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true} if the current user has opened the Screen Attention settings page
|
||||||
|
* before, otherwise {@code false}.
|
||||||
|
*/
|
||||||
|
private boolean isUserInteracted() {
|
||||||
|
return mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE).getBoolean(
|
||||||
|
PREF_KEY_INTERACTED, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The device is recently set up means its first settings-open time is within 2 weeks ago.
|
||||||
|
*
|
||||||
|
* @return {@code true} if the device is recently set up, otherwise {@code false}.
|
||||||
|
*/
|
||||||
|
private boolean isRecentlySetup() {
|
||||||
|
final long endTime = System.currentTimeMillis() - DEFERRED_TIME_DAYS;
|
||||||
|
final long firstSetupTime = mContext.getSharedPreferences(PREF,
|
||||||
|
Context.MODE_PRIVATE).getLong(PREF_KEY_SETUP_TIME, DEFAULT_SETUP_TIME);
|
||||||
|
return firstSetupTime > endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the screen attention settings is enabled. Contextual card will only appear
|
||||||
|
* when the screen attention settings is available.
|
||||||
|
*
|
||||||
|
* @return {@code true} if screen attention settings is enabled, otherwise {@code false}
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean isSettingsAvailable() {
|
||||||
|
return isControllerAvailable(mContext) == AVAILABLE;
|
||||||
|
}
|
||||||
|
}
|
@@ -26,6 +26,7 @@ import android.util.ArrayMap;
|
|||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
import com.android.settings.display.AdaptiveSleepPreferenceController;
|
||||||
import com.android.settings.flashlight.FlashlightSlice;
|
import com.android.settings.flashlight.FlashlightSlice;
|
||||||
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
|
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
|
||||||
import com.android.settings.homepage.contextualcards.deviceinfo.DataUsageSlice;
|
import com.android.settings.homepage.contextualcards.deviceinfo.DataUsageSlice;
|
||||||
@@ -34,6 +35,7 @@ import com.android.settings.homepage.contextualcards.deviceinfo.EmergencyInfoSli
|
|||||||
import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice;
|
import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice;
|
||||||
import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;
|
import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;
|
||||||
import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlice;
|
import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlice;
|
||||||
|
import com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice;
|
||||||
import com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice;
|
import com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice;
|
||||||
import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
|
import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
|
||||||
import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice;
|
import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice;
|
||||||
@@ -64,6 +66,16 @@ public class CustomSliceRegistry {
|
|||||||
.appendPath(SettingsSlicesContract.KEY_AIRPLANE_MODE)
|
.appendPath(SettingsSlicesContract.KEY_AIRPLANE_MODE)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uri for Contextual Adaptive Sleep Slice
|
||||||
|
*/
|
||||||
|
public static final Uri CONTEXTUAL_ADAPTIVE_SLEEP_URI = new Uri.Builder()
|
||||||
|
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
|
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
|
||||||
|
.appendPath(SettingsSlicesContract.PATH_SETTING_INTENT)
|
||||||
|
.appendPath(AdaptiveSleepPreferenceController.PREF_NAME)
|
||||||
|
.build();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uri for Battery Fix Slice.
|
* Uri for Battery Fix Slice.
|
||||||
*/
|
*/
|
||||||
@@ -328,6 +340,7 @@ public class CustomSliceRegistry {
|
|||||||
|
|
||||||
sUriToSlice.put(BATTERY_FIX_SLICE_URI, BatteryFixSlice.class);
|
sUriToSlice.put(BATTERY_FIX_SLICE_URI, BatteryFixSlice.class);
|
||||||
sUriToSlice.put(BLUETOOTH_DEVICES_SLICE_URI, BluetoothDevicesSlice.class);
|
sUriToSlice.put(BLUETOOTH_DEVICES_SLICE_URI, BluetoothDevicesSlice.class);
|
||||||
|
sUriToSlice.put(CONTEXTUAL_ADAPTIVE_SLEEP_URI, ContextualAdaptiveSleepSlice.class);
|
||||||
sUriToSlice.put(CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI,
|
sUriToSlice.put(CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI,
|
||||||
ContextualNotificationChannelSlice.class);
|
ContextualNotificationChannelSlice.class);
|
||||||
sUriToSlice.put(CONTEXTUAL_WIFI_SLICE_URI, ContextualWifiSlice.class);
|
sUriToSlice.put(CONTEXTUAL_WIFI_SLICE_URI, ContextualWifiSlice.class);
|
||||||
@@ -337,12 +350,12 @@ public class CustomSliceRegistry {
|
|||||||
sUriToSlice.put(FLASHLIGHT_SLICE_URI, FlashlightSlice.class);
|
sUriToSlice.put(FLASHLIGHT_SLICE_URI, FlashlightSlice.class);
|
||||||
sUriToSlice.put(LOCATION_SLICE_URI, LocationSlice.class);
|
sUriToSlice.put(LOCATION_SLICE_URI, LocationSlice.class);
|
||||||
sUriToSlice.put(LOW_STORAGE_SLICE_URI, LowStorageSlice.class);
|
sUriToSlice.put(LOW_STORAGE_SLICE_URI, LowStorageSlice.class);
|
||||||
|
sUriToSlice.put(MEDIA_OUTPUT_INDICATOR_SLICE_URI, MediaOutputIndicatorSlice.class);
|
||||||
|
sUriToSlice.put(MEDIA_OUTPUT_SLICE_URI, MediaOutputSlice.class);
|
||||||
sUriToSlice.put(MOBILE_DATA_SLICE_URI, MobileDataSlice.class);
|
sUriToSlice.put(MOBILE_DATA_SLICE_URI, MobileDataSlice.class);
|
||||||
sUriToSlice.put(NOTIFICATION_CHANNEL_SLICE_URI, NotificationChannelSlice.class);
|
sUriToSlice.put(NOTIFICATION_CHANNEL_SLICE_URI, NotificationChannelSlice.class);
|
||||||
sUriToSlice.put(STORAGE_SLICE_URI, StorageSlice.class);
|
sUriToSlice.put(STORAGE_SLICE_URI, StorageSlice.class);
|
||||||
sUriToSlice.put(WIFI_SLICE_URI, WifiSlice.class);
|
sUriToSlice.put(WIFI_SLICE_URI, WifiSlice.class);
|
||||||
sUriToSlice.put(MEDIA_OUTPUT_SLICE_URI, MediaOutputSlice.class);
|
|
||||||
sUriToSlice.put(MEDIA_OUTPUT_INDICATOR_SLICE_URI, MediaOutputIndicatorSlice.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Class<? extends CustomSliceable> getSliceClassByUri(Uri uri) {
|
public static Class<? extends CustomSliceable> getSliceClassByUri(Uri uri) {
|
||||||
|
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.homepage.contextualcards.slices;
|
||||||
|
|
||||||
|
import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.DEFERRED_TIME_DAYS;
|
||||||
|
import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.PREF;
|
||||||
|
import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.PREF_KEY_SETUP_TIME;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import androidx.slice.Slice;
|
||||||
|
import androidx.slice.SliceProvider;
|
||||||
|
import androidx.slice.widget.SliceLiveData;
|
||||||
|
|
||||||
|
import com.android.settings.slices.CustomSliceRegistry;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class ContextualAdaptiveSleepSliceTest {
|
||||||
|
|
||||||
|
private static final String pkgName = "adaptive_sleep";
|
||||||
|
private Context mContext;
|
||||||
|
private ContextualAdaptiveSleepSlice mContextualAdaptiveSleepSlice;
|
||||||
|
@Mock
|
||||||
|
private PackageManager mPackageManager;
|
||||||
|
@Mock
|
||||||
|
private SharedPreferences mSharedPreferences;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
|
||||||
|
mContext = spy(RuntimeEnvironment.application);
|
||||||
|
mContextualAdaptiveSleepSlice = spy(new ContextualAdaptiveSleepSlice(mContext));
|
||||||
|
|
||||||
|
doReturn(mPackageManager).when(mContext).getPackageManager();
|
||||||
|
doReturn(mSharedPreferences).when(mContext).getSharedPreferences(eq(PREF), anyInt());
|
||||||
|
doReturn(true).when(mContextualAdaptiveSleepSlice).isSettingsAvailable();
|
||||||
|
doReturn(pkgName).when(mPackageManager).getAttentionServicePackageName();
|
||||||
|
doReturn(-DEFERRED_TIME_DAYS).when(mSharedPreferences).getLong(eq(PREF_KEY_SETUP_TIME),
|
||||||
|
anyLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getUri_shouldReturnContextualAdaptiveSleepSliceUri() {
|
||||||
|
final Uri uri = mContextualAdaptiveSleepSlice.getUri();
|
||||||
|
|
||||||
|
assertThat(uri).isEqualTo(CustomSliceRegistry.CONTEXTUAL_ADAPTIVE_SLEEP_URI);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSlice_ShowIfFeatureIsAvailable() {
|
||||||
|
final Slice slice = mContextualAdaptiveSleepSlice.getSlice();
|
||||||
|
|
||||||
|
assertThat(slice).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSlice_DoNotShowIfFeatureIsUnavailable() {
|
||||||
|
doReturn(false).when(mContextualAdaptiveSleepSlice).isSettingsAvailable();
|
||||||
|
|
||||||
|
final Slice slice = mContextualAdaptiveSleepSlice.getSlice();
|
||||||
|
|
||||||
|
assertThat(slice).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSlice_ShowIfNotRecentlySetup() {
|
||||||
|
final Slice slice = mContextualAdaptiveSleepSlice.getSlice();
|
||||||
|
|
||||||
|
assertThat(slice).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getSlice_DoNotShowIfRecentlySetup() {
|
||||||
|
doReturn(System.currentTimeMillis()).when(mSharedPreferences).getLong(
|
||||||
|
eq(PREF_KEY_SETUP_TIME), anyLong());
|
||||||
|
|
||||||
|
final Slice slice = mContextualAdaptiveSleepSlice.getSlice();
|
||||||
|
|
||||||
|
assertThat(slice).isNull();
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user