• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }