Home | History | Annotate | Download | only in deletionhelper
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
      5  * except in compliance with the License. You may obtain a copy of the License at
      6  *
      7  *      http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the
     10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     11  * KIND, either express or implied. See the License for the specific language governing
     12  * permissions and limitations under the License.
     13  */
     14 
     15 package com.android.storagemanager.deletionhelper;
     16 
     17 import android.app.Activity;
     18 import android.app.AlertDialog;
     19 import android.app.Dialog;
     20 import android.app.DialogFragment;
     21 import android.content.Context;
     22 import android.content.DialogInterface;
     23 import android.content.SharedPreferences;
     24 import android.os.Bundle;
     25 import android.provider.Settings;
     26 import android.support.annotation.VisibleForTesting;
     27 import android.text.format.Formatter;
     28 import com.android.storagemanager.R;
     29 
     30 import java.util.concurrent.TimeUnit;
     31 
     32 /**
     33  * Fragment for activating the storage manager after a manual clear.
     34  */
     35 public class StorageManagerUpsellDialog extends DialogFragment
     36         implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
     37     public static final String TAG = "StorageManagerUpsellDialog";
     38     private static final String SHARED_PREFERENCES_NAME = "StorageManagerUpsellDialog";
     39     private static final String NEXT_SHOW_TIME = "next_show_time";
     40     private static final String DISMISSED_COUNT = "dismissed_count";
     41     private static final String NO_THANKS_COUNT = "no_thanks_count";
     42 
     43     private static final String ARGS_FREED_BYTES = "freed_bytes";
     44 
     45     private static final long NEVER = -1;
     46     private static final long DISMISS_SHORT_DELAY = TimeUnit.DAYS.toMillis(14);
     47     private static final long DISMISS_LONG_DELAY = TimeUnit.DAYS.toMillis(90);
     48     private static final int DISMISS_LONG_THRESHOLD = 9;
     49     private static final long NO_THANKS_SHORT_DELAY = TimeUnit.DAYS.toMillis(90);
     50     private static final long NO_THANKS_LONG_DELAY = NEVER;
     51     private static final int NO_THANKS_LONG_THRESHOLD = 3;
     52 
     53     private Clock mClock;
     54 
     55     public static StorageManagerUpsellDialog newInstance(long freedBytes) {
     56         StorageManagerUpsellDialog dialog = new StorageManagerUpsellDialog();
     57         Bundle args = new Bundle(1);
     58         args.putLong(ARGS_FREED_BYTES, freedBytes);
     59         dialog.setArguments(args);
     60         return dialog;
     61     }
     62 
     63     @VisibleForTesting(otherwise = VisibleForTesting.NONE)
     64     protected void setClock(Clock clock) {
     65         mClock = clock;
     66     }
     67 
     68     @Override
     69     public Dialog onCreateDialog(Bundle savedInstanceState) {
     70         final Bundle args = getArguments();
     71         long freedBytes = args.getLong(ARGS_FREED_BYTES);
     72 
     73         final Context context = getContext();
     74         return new AlertDialog.Builder(context)
     75                 .setTitle(context.getString(R.string.deletion_helper_upsell_title))
     76                 .setMessage(context.getString(R.string.deletion_helper_upsell_summary,
     77                         Formatter.formatFileSize(context, freedBytes)))
     78                 .setPositiveButton(R.string.deletion_helper_upsell_activate, this)
     79                 .setNegativeButton(R.string.deletion_helper_upsell_cancel, this)
     80                 .create();
     81     }
     82 
     83     @Override
     84     public void onClick(DialogInterface dialog, int buttonId) {
     85         if (buttonId == DialogInterface.BUTTON_POSITIVE) {
     86             Settings.Secure.putInt(getActivity().getContentResolver(),
     87                     Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED, 1);
     88         } else {
     89             SharedPreferences sp = getSharedPreferences(getContext());
     90             int noThanksCount = sp.getInt(NO_THANKS_COUNT, 0) + 1;
     91             SharedPreferences.Editor editor = sp.edit();
     92             editor.putInt(NO_THANKS_COUNT, noThanksCount);
     93             long noThanksDelay = getNoThanksDelay(noThanksCount);
     94             long nextShowTime = noThanksDelay == NEVER ? NEVER : getCurrentTime() + noThanksDelay;
     95             editor.putLong(NEXT_SHOW_TIME, nextShowTime);
     96             editor.apply();
     97         }
     98 
     99         finishActivity();
    100     }
    101 
    102     @Override
    103     public void onCancel(DialogInterface dialog) {
    104         SharedPreferences sp = getSharedPreferences(getContext());
    105         int dismissCount = sp.getInt(DISMISSED_COUNT, 0) + 1;
    106         SharedPreferences.Editor editor = sp.edit();
    107         editor.putInt(DISMISSED_COUNT, dismissCount);
    108         editor.putLong(NEXT_SHOW_TIME, getCurrentTime() + getDismissDelay(dismissCount));
    109         editor.apply();
    110 
    111         finishActivity();
    112     }
    113 
    114     /**
    115      * Returns if the dialog should be shown, given the delays between when it is shown.
    116      * @param context Context to get shared preferences for determining the next show time.
    117      * @param time The current time in millis.
    118      */
    119     public static boolean shouldShow(Context context, long time) {
    120         boolean isEnabled =
    121                 Settings.Secure.getInt(context.getContentResolver(),
    122                         Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED, 0) != 0;
    123         if (isEnabled) {
    124             return false;
    125         }
    126 
    127         long nextTimeToShow = getSharedPreferences(context).getLong(NEXT_SHOW_TIME, 0);
    128         if (nextTimeToShow == NEVER) {
    129             return false;
    130         }
    131 
    132         return time >= nextTimeToShow;
    133     }
    134 
    135     private static SharedPreferences getSharedPreferences(Context context) {
    136         return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
    137     }
    138 
    139     private static long getNoThanksDelay(int noThanksCount) {
    140         return (noThanksCount > NO_THANKS_LONG_THRESHOLD)
    141                 ? NO_THANKS_LONG_DELAY : NO_THANKS_SHORT_DELAY;
    142     }
    143 
    144     private static long getDismissDelay(int dismissCount) {
    145         return (dismissCount > DISMISS_LONG_THRESHOLD)
    146                 ? DISMISS_LONG_DELAY : DISMISS_SHORT_DELAY;
    147     }
    148 
    149     private void finishActivity() {
    150         Activity activity = getActivity();
    151         if (activity != null) {
    152             activity.finish();
    153         }
    154     }
    155 
    156     private long getCurrentTime() {
    157         if (mClock == null) {
    158             mClock = new Clock();
    159         }
    160 
    161         return mClock.currentTimeMillis();
    162     }
    163 
    164     /**
    165      * Clock provides the current time.
    166      */
    167     protected static class Clock {
    168         /**
    169          * Returns the current time in milliseconds.
    170          */
    171         public long currentTimeMillis() {
    172             return System.currentTimeMillis();
    173         }
    174     }
    175 }
    176