Home | History | Annotate | Download | only in quicksearchbox
      1 /*
      2  * Copyright (C) 2009 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.quicksearchbox;
     18 
     19 import com.android.common.SharedPreferencesCompat;
     20 
     21 import android.app.SearchManager;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.SharedPreferences;
     25 import android.content.SharedPreferences.Editor;
     26 import android.util.Log;
     27 import android.view.Menu;
     28 import android.view.MenuInflater;
     29 import android.view.MenuItem;
     30 
     31 /**
     32  * Manages user settings.
     33  */
     34 public class SearchSettingsImpl implements SearchSettings {
     35 
     36     private static final boolean DBG = false;
     37     private static final String TAG = "QSB.SearchSettingsImpl";
     38 
     39     // Name of the preferences file used to store search preference
     40     public static final String PREFERENCES_NAME = "SearchSettings";
     41 
     42     // Intent action that opens the "Searchable Items" preference
     43     private static final String ACTION_SEARCHABLE_ITEMS =
     44             "com.android.quicksearchbox.action.SEARCHABLE_ITEMS";
     45 
     46     /**
     47      * Preference key used for storing the index of the next voice search hint to show.
     48      */
     49     private static final String NEXT_VOICE_SEARCH_HINT_INDEX_PREF = "next_voice_search_hint";
     50 
     51     /**
     52      * Preference key used to store the time at which the first voice search hint was displayed.
     53      */
     54     private static final String FIRST_VOICE_HINT_DISPLAY_TIME = "first_voice_search_hint_time";
     55 
     56     /**
     57      * Preference key for the version of voice search we last got hints from.
     58      */
     59     private static final String LAST_SEEN_VOICE_SEARCH_VERSION = "voice_search_version";
     60 
     61     /**
     62      * Preference key for storing whether searches always go to google.com. Public
     63      * so that it can be used by PreferenceControllers.
     64      */
     65     public static final String USE_GOOGLE_COM_PREF = "use_google_com";
     66 
     67     /**
     68      * Preference key for the base search URL. This value is normally set by
     69      * a SearchBaseUrlHelper instance. Public so classes can listen to changes
     70      * on this key.
     71      */
     72     public static final String SEARCH_BASE_DOMAIN_PREF = "search_base_domain";
     73 
     74     /**
     75      * This is the time at which the base URL was stored, and is set using
     76      * @link{System.currentTimeMillis()}.
     77      */
     78     private static final String SEARCH_BASE_DOMAIN_APPLY_TIME = "search_base_domain_apply_time";
     79 
     80     /**
     81      * Prefix of per-corpus enable preference
     82      */
     83     private static final String CORPUS_ENABLED_PREF_PREFIX = "enable_corpus_";
     84 
     85     private final Context mContext;
     86 
     87     private final Config mConfig;
     88 
     89     public SearchSettingsImpl(Context context, Config config) {
     90         mContext = context;
     91         mConfig = config;
     92     }
     93 
     94     protected Context getContext() {
     95         return mContext;
     96     }
     97 
     98     protected Config getConfig() {
     99         return mConfig;
    100     }
    101 
    102     public void upgradeSettingsIfNeeded() {
    103     }
    104 
    105     public Intent getSearchableItemsIntent() {
    106         Intent intent = new Intent(ACTION_SEARCHABLE_ITEMS);
    107         intent.setPackage(getContext().getPackageName());
    108         return intent;
    109     }
    110 
    111     /**
    112      * Gets the preference key of the preference for whether the given corpus
    113      * is enabled. The preference is stored in the {@link #PREFERENCES_NAME}
    114      * preferences file.
    115      */
    116     public static String getCorpusEnabledPreference(Corpus corpus) {
    117         return CORPUS_ENABLED_PREF_PREFIX + corpus.getName();
    118     }
    119 
    120     public boolean isCorpusEnabled(Corpus corpus) {
    121         boolean defaultEnabled = corpus.isCorpusDefaultEnabled();
    122         String sourceEnabledPref = getCorpusEnabledPreference(corpus);
    123         return getSearchPreferences().getBoolean(sourceEnabledPref, defaultEnabled);
    124     }
    125 
    126     public SharedPreferences getSearchPreferences() {
    127         return getContext().getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
    128     }
    129 
    130     protected void storeBoolean(String name, boolean value) {
    131         SharedPreferencesCompat.apply(getSearchPreferences().edit().putBoolean(name, value));
    132     }
    133 
    134     protected void storeInt(String name, int value) {
    135         SharedPreferencesCompat.apply(getSearchPreferences().edit().putInt(name, value));
    136     }
    137 
    138     protected void storeLong(String name, long value) {
    139         SharedPreferencesCompat.apply(getSearchPreferences().edit().putLong(name, value));
    140     }
    141 
    142     protected void storeString(String name, String value) {
    143         SharedPreferencesCompat.apply(getSearchPreferences().edit().putString(name, value));
    144     }
    145 
    146     protected void removePref(String name) {
    147         SharedPreferencesCompat.apply(getSearchPreferences().edit().remove(name));
    148     }
    149 
    150     /**
    151      * Informs our listeners about the updated settings data.
    152      */
    153     public void broadcastSettingsChanged() {
    154         // We use a message broadcast since the listeners could be in multiple processes.
    155         Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS_CHANGED);
    156         Log.i(TAG, "Broadcasting: " + intent);
    157         getContext().sendBroadcast(intent);
    158     }
    159 
    160     public void addMenuItems(Menu menu, boolean showDisabled) {
    161         MenuInflater inflater = new MenuInflater(getContext());
    162         inflater.inflate(R.menu.settings, menu);
    163         MenuItem item = menu.findItem(R.id.menu_settings);
    164         item.setIntent(getSearchSettingsIntent());
    165     }
    166 
    167     public Intent getSearchSettingsIntent() {
    168         Intent settings = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS);
    169         settings.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
    170         settings.setPackage(getContext().getPackageName());
    171         return settings;
    172     }
    173 
    174     public int getNextVoiceSearchHintIndex(int size) {
    175             int i = getAndIncrementIntPreference(getSearchPreferences(),
    176                     NEXT_VOICE_SEARCH_HINT_INDEX_PREF);
    177             return i % size;
    178     }
    179 
    180     // TODO: Could this be made atomic to avoid races?
    181     private int getAndIncrementIntPreference(SharedPreferences prefs, String name) {
    182         int i = prefs.getInt(name, 0);
    183         storeInt(name, i + 1);
    184         return i;
    185     }
    186 
    187     public void resetVoiceSearchHintFirstSeenTime() {
    188         storeLong(FIRST_VOICE_HINT_DISPLAY_TIME, System.currentTimeMillis());
    189     }
    190 
    191     public boolean haveVoiceSearchHintsExpired(int currentVoiceSearchVersion) {
    192         SharedPreferences prefs = getSearchPreferences();
    193 
    194         if (currentVoiceSearchVersion != 0) {
    195             long currentTime = System.currentTimeMillis();
    196             int lastVoiceSearchVersion = prefs.getInt(LAST_SEEN_VOICE_SEARCH_VERSION, 0);
    197             long firstHintTime = prefs.getLong(FIRST_VOICE_HINT_DISPLAY_TIME, 0);
    198             if (firstHintTime == 0 || currentVoiceSearchVersion != lastVoiceSearchVersion) {
    199                 SharedPreferencesCompat.apply(prefs.edit()
    200                         .putInt(LAST_SEEN_VOICE_SEARCH_VERSION, currentVoiceSearchVersion)
    201                         .putLong(FIRST_VOICE_HINT_DISPLAY_TIME, currentTime));
    202                 firstHintTime = currentTime;
    203             }
    204             if (currentTime - firstHintTime > getConfig().getVoiceSearchHintActivePeriod()) {
    205                 if (DBG) Log.d(TAG, "Voice seach hint period expired; not showing hints.");
    206                 return true;
    207             } else {
    208                 return false;
    209             }
    210         } else {
    211             if (DBG) Log.d(TAG, "Could not determine voice search version; not showing hints.");
    212             return true;
    213         }
    214     }
    215 
    216     public boolean allowWebSearchShortcuts() {
    217         return true;
    218     }
    219 
    220     /**
    221      * @return true if user searches should always be based at google.com, false
    222      *     otherwise.
    223      */
    224     @Override
    225     public boolean shouldUseGoogleCom() {
    226         // Note that this preserves the old behaviour of using google.com
    227         // for searches, with the gl= parameter set.
    228         return getSearchPreferences().getBoolean(USE_GOOGLE_COM_PREF, true);
    229     }
    230 
    231     @Override
    232     public void setUseGoogleCom(boolean useGoogleCom) {
    233         storeBoolean(USE_GOOGLE_COM_PREF, useGoogleCom);
    234     }
    235 
    236     @Override
    237     public long getSearchBaseDomainApplyTime() {
    238         return getSearchPreferences().getLong(SEARCH_BASE_DOMAIN_APPLY_TIME, -1);
    239     }
    240 
    241     @Override
    242     public String getSearchBaseDomain() {
    243         // Note that the only time this will return null is on the first run
    244         // of the app, or when settings have been cleared. Callers should
    245         // ideally check that getSearchBaseDomainApplyTime() is not -1 before
    246         // calling this function.
    247         return getSearchPreferences().getString(SEARCH_BASE_DOMAIN_PREF, null);
    248     }
    249 
    250     @Override
    251     public void setSearchBaseDomain(String searchBaseUrl) {
    252         Editor sharedPrefEditor = getSearchPreferences().edit();
    253         sharedPrefEditor.putString(SEARCH_BASE_DOMAIN_PREF, searchBaseUrl);
    254         sharedPrefEditor.putLong(SEARCH_BASE_DOMAIN_APPLY_TIME, System.currentTimeMillis());
    255 
    256         SharedPreferencesCompat.apply(sharedPrefEditor);
    257     }
    258 }
    259