| /* |
| * Copyright (C) 2016 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.storagemanager.automatic; |
| |
| import android.app.Notification; |
| import android.app.NotificationManager; |
| import android.app.PendingIntent; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.SharedPreferences; |
| import android.content.res.Resources; |
| import android.os.SystemProperties; |
| import android.provider.Settings; |
| |
| import com.android.storagemanager.R; |
| import com.android.storagemanager.automatic.WarningDialogActivity; |
| import com.android.storagemanager.overlay.FeatureFactory; |
| |
| import java.util.concurrent.TimeUnit; |
| |
| /** |
| * NotificationController handles the responses to the Automatic Storage Management low storage |
| * notification. |
| */ |
| public class NotificationController extends BroadcastReceiver { |
| /** |
| * Intent action for if the user taps "Turn on" for the automatic storage manager. |
| */ |
| public static final String INTENT_ACTION_ACTIVATE_ASM = |
| "com.android.storagemanager.automatic.ACTIVATE"; |
| |
| /** |
| * Intent action for if the user swipes the notification away. |
| */ |
| public static final String INTENT_ACTION_DISMISS = |
| "com.android.storagemanager.automatic.DISMISS"; |
| |
| /** |
| * Intent action for if the user explicitly hits "No thanks" on the notification. |
| */ |
| public static final String INTENT_ACTION_NO_THANKS = |
| "com.android.storagemanager.automatic.NO_THANKS"; |
| |
| /** |
| * Intent action for forcefully showing the notification, even if the conditions are not valid. |
| */ |
| private static final String INTENT_ACTION_DEBUG_NOTIFICATION = |
| "com.android.storagemanager.automatic.DEBUG_SHOW_NOTIFICATION"; |
| |
| /** |
| * Intent action for if the user taps on the notification. |
| */ |
| private static final String INTENT_ACTION_TAP = |
| "com.android.storagemanager.automatic.SHOW_SETTINGS"; |
| |
| /** |
| * Intent extra for the notification id. |
| */ |
| public static final String INTENT_EXTRA_ID = "id"; |
| |
| private static final String SHARED_PREFERENCES_NAME = "NotificationController"; |
| private static final String NOTIFICATION_NEXT_SHOW_TIME = "notification_next_show_time"; |
| private static final String NOTIFICATION_SHOWN_COUNT = "notification_shown_count"; |
| private static final String NOTIFICATION_DISMISS_COUNT = "notification_dismiss_count"; |
| private static final String STORAGE_MANAGER_PROPERTY = "ro.storage_manager.enabled"; |
| |
| private static final long DISMISS_DELAY = TimeUnit.DAYS.toMillis(15); |
| private static final long NO_THANKS_DELAY = TimeUnit.DAYS.toMillis(90); |
| private static final long MAXIMUM_SHOWN_COUNT = 4; |
| private static final long MAXIMUM_DISMISS_COUNT = 9; |
| private static final int NOTIFICATION_ID = 0; |
| |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| switch (intent.getAction()) { |
| case INTENT_ACTION_ACTIVATE_ASM: |
| Settings.Secure.putInt(context.getContentResolver(), |
| Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED, |
| 1); |
| // Provide a warning if storage manager is not defaulted on. |
| if (!SystemProperties.getBoolean(STORAGE_MANAGER_PROPERTY, false)) { |
| Intent warningIntent = new Intent(context, WarningDialogActivity.class); |
| context.startActivity(warningIntent); |
| } |
| break; |
| case INTENT_ACTION_NO_THANKS: |
| delayNextNotification(context, NO_THANKS_DELAY); |
| break; |
| case INTENT_ACTION_DISMISS: |
| delayNextNotification(context, DISMISS_DELAY); |
| break; |
| case INTENT_ACTION_DEBUG_NOTIFICATION: |
| showNotification(context); |
| return; |
| case INTENT_ACTION_TAP: |
| Intent storageIntent = new Intent(Settings.ACTION_STORAGE_MANAGER_SETTINGS); |
| storageIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| context.startActivity(storageIntent); |
| break; |
| } |
| cancelNotification(context, intent); |
| } |
| |
| /** |
| * If the conditions for showing the activation notification are met, show the activation |
| * notification. |
| * @param context Context to use for getting resources and to display the notification. |
| */ |
| public static void maybeShowNotification(Context context) { |
| if (shouldShowNotification(context)) { |
| showNotification(context); |
| } |
| } |
| |
| private static boolean shouldShowNotification(Context context) { |
| SharedPreferences sp = context.getSharedPreferences( |
| SHARED_PREFERENCES_NAME, |
| Context.MODE_PRIVATE); |
| int timesShown = sp.getInt(NOTIFICATION_SHOWN_COUNT, 0); |
| int timesDismissed = sp.getInt(NOTIFICATION_DISMISS_COUNT, 0); |
| if (timesShown >= MAXIMUM_SHOWN_COUNT || timesDismissed >= MAXIMUM_DISMISS_COUNT) { |
| return false; |
| } |
| |
| long nextTimeToShow = sp.getLong(NOTIFICATION_NEXT_SHOW_TIME, 0); |
| |
| return System.currentTimeMillis() > nextTimeToShow; |
| } |
| |
| private static void showNotification(Context context) { |
| Resources res = context.getResources(); |
| Intent noThanksIntent = new Intent(INTENT_ACTION_NO_THANKS); |
| noThanksIntent.putExtra(INTENT_EXTRA_ID, NOTIFICATION_ID); |
| Notification.Action.Builder cancelAction = new Notification.Action.Builder(null, |
| res.getString(R.string.automatic_storage_manager_cancel_button), |
| PendingIntent.getBroadcast(context, 0, noThanksIntent, |
| PendingIntent.FLAG_UPDATE_CURRENT)); |
| |
| |
| Intent activateIntent = new Intent(INTENT_ACTION_ACTIVATE_ASM); |
| activateIntent.putExtra(INTENT_EXTRA_ID, NOTIFICATION_ID); |
| Notification.Action.Builder activateAutomaticAction = new Notification.Action.Builder(null, |
| res.getString(R.string.automatic_storage_manager_activate_button), |
| PendingIntent.getBroadcast(context, 0, activateIntent, |
| PendingIntent.FLAG_UPDATE_CURRENT)); |
| |
| Intent dismissIntent = new Intent(INTENT_ACTION_DISMISS); |
| dismissIntent.putExtra(INTENT_EXTRA_ID, NOTIFICATION_ID); |
| PendingIntent deleteIntent = PendingIntent.getBroadcast(context, 0, |
| dismissIntent, |
| PendingIntent.FLAG_ONE_SHOT); |
| |
| Intent contentIntent = new Intent(INTENT_ACTION_TAP); |
| contentIntent.putExtra(INTENT_EXTRA_ID, NOTIFICATION_ID); |
| PendingIntent tapIntent = PendingIntent.getBroadcast(context, 0, contentIntent, |
| PendingIntent.FLAG_ONE_SHOT); |
| |
| Notification.Builder builder = new Notification.Builder(context) |
| .setSmallIcon(R.drawable.ic_settings_24dp) |
| .setContentTitle( |
| res.getString(R.string.automatic_storage_manager_notification_title)) |
| .setContentText( |
| res.getString(R.string.automatic_storage_manager_notification_summary)) |
| .setStyle(new Notification.BigTextStyle().bigText( |
| res.getString(R.string.automatic_storage_manager_notification_summary))) |
| .addAction(cancelAction.build()) |
| .addAction(activateAutomaticAction.build()) |
| .setContentIntent(tapIntent) |
| .setDeleteIntent(deleteIntent); |
| |
| NotificationManager manager = |
| ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)); |
| manager.notify(NOTIFICATION_ID, builder.build()); |
| } |
| |
| private void cancelNotification(Context context, Intent intent) { |
| if (intent.getAction() == INTENT_ACTION_DISMISS) { |
| incrementNotificationDismissedCount(context); |
| } else { |
| incrementNotificationShownCount(context); |
| } |
| |
| int id = intent.getIntExtra(INTENT_EXTRA_ID, -1); |
| if (id == -1) { |
| return; |
| } |
| NotificationManager manager = (NotificationManager) context |
| .getSystemService(Context.NOTIFICATION_SERVICE); |
| manager.cancel(id); |
| } |
| |
| private void incrementNotificationShownCount(Context context) { |
| SharedPreferences sp = context.getSharedPreferences(SHARED_PREFERENCES_NAME, |
| Context.MODE_PRIVATE); |
| SharedPreferences.Editor editor = sp.edit(); |
| int shownCount = sp.getInt(NotificationController.NOTIFICATION_SHOWN_COUNT, 0) + 1; |
| editor.putInt(NotificationController.NOTIFICATION_SHOWN_COUNT, shownCount); |
| editor.apply(); |
| } |
| |
| private void incrementNotificationDismissedCount(Context context) { |
| SharedPreferences sp = context.getSharedPreferences(SHARED_PREFERENCES_NAME, |
| Context.MODE_PRIVATE); |
| SharedPreferences.Editor editor = sp.edit(); |
| int dismissCount = sp.getInt(NOTIFICATION_DISMISS_COUNT, 0) + 1; |
| editor.putInt(NOTIFICATION_DISMISS_COUNT, dismissCount); |
| editor.apply(); |
| } |
| |
| private void delayNextNotification(Context context, long timeInMillis) { |
| SharedPreferences sp = context.getSharedPreferences(SHARED_PREFERENCES_NAME, |
| Context.MODE_PRIVATE); |
| SharedPreferences.Editor editor = sp.edit(); |
| editor.putLong(NOTIFICATION_NEXT_SHOW_TIME, |
| System.currentTimeMillis() + timeInMillis); |
| editor.apply(); |
| } |
| } |