1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.settings.homepage.contextualcards.slices; 18 19 import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; 20 import static com.android.settings.display.AdaptiveSleepPreferenceController.isControllerAvailable; 21 import static com.android.settings.display.ScreenTimeoutPreferenceController.PREF_NAME; 22 import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_ADAPTIVE_SLEEP_URI; 23 24 import android.app.PendingIntent; 25 import android.app.settings.SettingsEnums; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.net.Uri; 29 import android.provider.Settings; 30 31 import androidx.core.graphics.drawable.IconCompat; 32 import androidx.slice.Slice; 33 import androidx.slice.builders.ListBuilder; 34 import androidx.slice.builders.SliceAction; 35 36 import com.android.settings.R; 37 import com.android.settings.SubSettings; 38 import com.android.settings.display.ScreenTimeoutSettings; 39 import com.android.settings.slices.CustomSliceable; 40 import com.android.settings.slices.SliceBuilderUtils; 41 42 import com.google.common.annotations.VisibleForTesting; 43 44 import java.util.concurrent.TimeUnit; 45 46 // TODO(b/172310863): consider removing this slice. 47 public class ContextualAdaptiveSleepSlice implements CustomSliceable { 48 private static final String TAG = "ContextualAdaptiveSleepSlice"; 49 private static final long DEFAULT_SETUP_TIME = 0; 50 private Context mContext; 51 52 @VisibleForTesting 53 static final long DEFERRED_TIME_DAYS = TimeUnit.DAYS.toMillis(14); 54 @VisibleForTesting 55 static final String PREF_KEY_SETUP_TIME = "adaptive_sleep_setup_time"; 56 57 public static final String PREF_KEY_INTERACTED = "adaptive_sleep_interacted"; 58 public static final String PREF = "adaptive_sleep_slice"; 59 ContextualAdaptiveSleepSlice(Context context)60 public ContextualAdaptiveSleepSlice(Context context) { 61 mContext = context; 62 } 63 64 @Override getSlice()65 public Slice getSlice() { 66 final long setupTime = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE).getLong( 67 PREF_KEY_SETUP_TIME, DEFAULT_SETUP_TIME); 68 if (setupTime == DEFAULT_SETUP_TIME) { 69 // Set the first setup time. 70 mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE) 71 .edit() 72 .putLong(PREF_KEY_SETUP_TIME, System.currentTimeMillis()) 73 .apply(); 74 return null; 75 } 76 77 // Display the contextual card only if all the following 4 conditions hold: 78 // 1. The Screen Attention is available in Settings. 79 // 2. The device is not recently set up. 80 // 3. Current user hasn't opened Screen Attention's settings page before. 81 // 4. Screen Attention is off. 82 if (isSettingsAvailable() && !isUserInteracted() && !isRecentlySetup() && !isTurnedOn()) { 83 final IconCompat icon = IconCompat.createWithResource(mContext, 84 R.drawable.ic_settings_adaptive_sleep); 85 final CharSequence title = 86 mContext.getText(R.string.adaptive_sleep_contextual_slice_title); 87 final CharSequence subtitle = mContext.getText( 88 R.string.adaptive_sleep_contextual_slice_summary); 89 90 final SliceAction pAction = SliceAction.createDeeplink(getPrimaryAction(), 91 icon, 92 ListBuilder.ICON_IMAGE, 93 title); 94 final ListBuilder listBuilder = new ListBuilder(mContext, 95 CONTEXTUAL_ADAPTIVE_SLEEP_URI, 96 ListBuilder.INFINITY) 97 .setAccentColor(COLOR_NOT_TINTED) 98 .addRow(new ListBuilder.RowBuilder() 99 .setTitleItem(icon, ListBuilder.ICON_IMAGE) 100 .setTitle(title) 101 .setSubtitle(subtitle) 102 .setPrimaryAction(pAction)); 103 return listBuilder.build(); 104 } else { 105 return null; 106 } 107 } 108 109 @Override getUri()110 public Uri getUri() { 111 return CONTEXTUAL_ADAPTIVE_SLEEP_URI; 112 } 113 114 @Override getIntent()115 public Intent getIntent() { 116 final CharSequence screenTitle = mContext.getText(R.string.adaptive_sleep_title); 117 final Uri contentUri = new Uri.Builder().appendPath(PREF_NAME).build(); 118 return SliceBuilderUtils.buildSearchResultPageIntent(mContext, 119 ScreenTimeoutSettings.class.getName(), PREF_NAME, screenTitle.toString(), 120 SettingsEnums.SLICE, this) 121 .setClassName(mContext.getPackageName(), 122 SubSettings.class.getName()).setData(contentUri); 123 } 124 125 @Override getSliceHighlightMenuRes()126 public int getSliceHighlightMenuRes() { 127 return R.string.menu_key_display; 128 } 129 getPrimaryAction()130 private PendingIntent getPrimaryAction() { 131 final Intent intent = getIntent(); 132 return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 133 PendingIntent.FLAG_IMMUTABLE /* flags */); 134 } 135 136 /** 137 * @return {@code true} if the feature is turned on for the device, otherwise {@code false} 138 */ isTurnedOn()139 private boolean isTurnedOn() { 140 return Settings.Secure.getInt( 141 mContext.getContentResolver(), Settings.Secure.ADAPTIVE_SLEEP, 0) != 0; 142 } 143 144 /** 145 * @return {@code true} if the current user has opened the Screen Attention settings page 146 * before, otherwise {@code false}. 147 */ isUserInteracted()148 private boolean isUserInteracted() { 149 return mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE).getBoolean( 150 PREF_KEY_INTERACTED, false); 151 } 152 153 /** 154 * The device is recently set up means its first settings-open time is within 2 weeks ago. 155 * 156 * @return {@code true} if the device is recently set up, otherwise {@code false}. 157 */ isRecentlySetup()158 private boolean isRecentlySetup() { 159 final long endTime = System.currentTimeMillis() - DEFERRED_TIME_DAYS; 160 final long firstSetupTime = mContext.getSharedPreferences(PREF, 161 Context.MODE_PRIVATE).getLong(PREF_KEY_SETUP_TIME, DEFAULT_SETUP_TIME); 162 return firstSetupTime > endTime; 163 } 164 165 /** 166 * Check whether the screen attention settings is enabled. Contextual card will only appear 167 * when the screen attention settings is available. 168 * 169 * @return {@code true} if screen attention settings is enabled, otherwise {@code false} 170 */ 171 @VisibleForTesting isSettingsAvailable()172 boolean isSettingsAvailable() { 173 return isControllerAvailable(mContext) == AVAILABLE_UNSEARCHABLE; 174 } 175 }