1 /* 2 * Copyright (C) 2016 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.storagemanager.automatic; 18 19 import android.app.Notification; 20 import android.app.NotificationManager; 21 import android.app.PendingIntent; 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.SharedPreferences; 26 import android.content.res.Resources; 27 import android.provider.Settings; 28 29 import com.android.storagemanager.R; 30 31 import java.util.concurrent.TimeUnit; 32 33 /** 34 * NotificationController handles the responses to the Automatic Storage Management low storage 35 * notification. 36 */ 37 public class NotificationController extends BroadcastReceiver { 38 /** 39 * Intent action for if the user taps "Turn on" for the automatic storage manager. 40 */ 41 public static final String INTENT_ACTION_ACTIVATE_ASM = 42 "com.android.storagemanager.automatic.ACTIVATE"; 43 44 /** 45 * Intent action for if the user swipes the notification away. 46 */ 47 public static final String INTENT_ACTION_DISMISS = 48 "com.android.storagemanager.automatic.DISMISS"; 49 50 /** 51 * Intent action for if the user explicitly hits "No thanks" on the notification. 52 */ 53 public static final String INTENT_ACTION_NO_THANKS = 54 "com.android.storagemanager.automatic.NO_THANKS"; 55 56 57 /** 58 * Intent action for if the user explicitly hits "No thanks" on the notification. 59 */ 60 private static final String INTENT_ACTION_DEBUG_NOTIFICATION = 61 "com.android.storagemanager.automatic.DEBUG_SHOW_NOTIFICATION"; 62 63 /** 64 * Intent extra for the notification id. 65 */ 66 public static final String INTENT_EXTRA_ID = "id"; 67 68 private static final String SHARED_PREFERENCES_NAME = "NotificationController"; 69 private static final String NOTIFICATION_NEXT_SHOW_TIME = "notification_next_show_time"; 70 private static final String NOTIFICATION_SHOWN_COUNT = "notification_shown_count"; 71 72 private static final long DISMISS_DELAY = TimeUnit.DAYS.toMillis(15); 73 private static final long NO_THANKS_DELAY = TimeUnit.DAYS.toMillis(90); 74 private static final long MAXIMUM_SHOWN_COUNT = 4; 75 private static final int NOTIFICATION_ID = 0; 76 77 @Override onReceive(Context context, Intent intent)78 public void onReceive(Context context, Intent intent) { 79 switch (intent.getAction()) { 80 case INTENT_ACTION_ACTIVATE_ASM: 81 Settings.Secure.putInt(context.getContentResolver(), 82 Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED, 83 1); 84 break; 85 case INTENT_ACTION_NO_THANKS: 86 delayNextNotification(context, NO_THANKS_DELAY); 87 break; 88 case INTENT_ACTION_DISMISS: 89 delayNextNotification(context, DISMISS_DELAY); 90 break; 91 case INTENT_ACTION_DEBUG_NOTIFICATION: 92 showNotification(context); 93 return; 94 } 95 cancelNotification(context, intent); 96 } 97 98 /** 99 * If the conditions for showing the activation notification are met, show the activation 100 * notification. 101 * @param context Context to use for getting resources and to display the notification. 102 */ maybeShowNotification(Context context)103 public static void maybeShowNotification(Context context) { 104 if (shouldShowNotification(context)) { 105 showNotification(context); 106 } 107 } 108 shouldShowNotification(Context context)109 private static boolean shouldShowNotification(Context context) { 110 SharedPreferences sp = context.getSharedPreferences( 111 SHARED_PREFERENCES_NAME, 112 Context.MODE_PRIVATE); 113 int timesShown = sp.getInt(NOTIFICATION_SHOWN_COUNT, 0); 114 if (timesShown > MAXIMUM_SHOWN_COUNT) { 115 return false; 116 } 117 118 long nextTimeToShow = sp.getLong(NOTIFICATION_NEXT_SHOW_TIME, 0); 119 120 return System.currentTimeMillis() > nextTimeToShow; 121 } 122 showNotification(Context context)123 private static void showNotification(Context context) { 124 Resources res = context.getResources(); 125 Intent noThanksIntent = new Intent(INTENT_ACTION_NO_THANKS); 126 noThanksIntent.putExtra(INTENT_EXTRA_ID, NOTIFICATION_ID); 127 Notification.Action.Builder cancelAction = new Notification.Action.Builder(null, 128 res.getString(R.string.automatic_storage_manager_cancel_button), 129 PendingIntent.getBroadcast(context, 0, noThanksIntent, 130 PendingIntent.FLAG_UPDATE_CURRENT)); 131 132 133 Intent activateIntent = new Intent(INTENT_ACTION_ACTIVATE_ASM); 134 activateIntent.putExtra(INTENT_EXTRA_ID, NOTIFICATION_ID); 135 Notification.Action.Builder activateAutomaticAction = new Notification.Action.Builder(null, 136 res.getString(R.string.automatic_storage_manager_activate_button), 137 PendingIntent.getBroadcast(context, 0, activateIntent, 138 PendingIntent.FLAG_UPDATE_CURRENT)); 139 140 Intent dismissIntent = new Intent(INTENT_ACTION_DISMISS); 141 dismissIntent.putExtra(INTENT_EXTRA_ID, NOTIFICATION_ID); 142 PendingIntent deleteIntent = PendingIntent.getBroadcast(context, 0, 143 new Intent(INTENT_ACTION_DISMISS), 144 PendingIntent.FLAG_ONE_SHOT); 145 146 Notification.Builder builder = new Notification.Builder(context) 147 .setSmallIcon(R.drawable.ic_settings_24dp) 148 .setContentTitle( 149 res.getString(R.string.automatic_storage_manager_notification_title)) 150 .setContentText( 151 res.getString(R.string.automatic_storage_manager_notification_summary)) 152 .setStyle(new Notification.BigTextStyle().bigText( 153 res.getString(R.string.automatic_storage_manager_notification_summary))) 154 .addAction(cancelAction.build()) 155 .addAction(activateAutomaticAction.build()) 156 .setDeleteIntent(deleteIntent); 157 158 NotificationManager manager = 159 ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)); 160 manager.notify(NOTIFICATION_ID, builder.build()); 161 } 162 cancelNotification(Context context, Intent intent)163 private void cancelNotification(Context context, Intent intent) { 164 int id = intent.getIntExtra(INTENT_EXTRA_ID, -1); 165 if (id == -1) { 166 return; 167 } 168 NotificationManager manager = (NotificationManager) context 169 .getSystemService(Context.NOTIFICATION_SERVICE); 170 manager.cancel(id); 171 172 incrementNotificationShownCount(context); 173 } 174 incrementNotificationShownCount(Context context)175 private void incrementNotificationShownCount(Context context) { 176 SharedPreferences sp = context.getSharedPreferences(SHARED_PREFERENCES_NAME, 177 Context.MODE_PRIVATE); 178 SharedPreferences.Editor editor = sp.edit(); 179 int shownCount = sp.getInt(NotificationController.NOTIFICATION_SHOWN_COUNT, 0) + 1; 180 editor.putInt(NotificationController.NOTIFICATION_SHOWN_COUNT, shownCount); 181 editor.apply(); 182 } 183 delayNextNotification(Context context, long timeInMillis)184 private void delayNextNotification(Context context, long timeInMillis) { 185 SharedPreferences sp = context.getSharedPreferences(SHARED_PREFERENCES_NAME, 186 Context.MODE_PRIVATE); 187 SharedPreferences.Editor editor = sp.edit(); 188 editor.putLong(NOTIFICATION_NEXT_SHOW_TIME, 189 System.currentTimeMillis() + timeInMillis); 190 editor.apply(); 191 } 192 } 193