1/* 2 * Copyright (C) 2017 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 17package com.android.settings.dashboard.suggestions; 18 19import android.app.ActivityManager; 20import android.content.ComponentName; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.SharedPreferences; 24import android.content.pm.PackageManager; 25import android.provider.Settings.Secure; 26import android.support.annotation.NonNull; 27import android.support.annotation.VisibleForTesting; 28import android.util.Log; 29import android.util.Pair; 30 31import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 32import com.android.settings.Settings.AmbientDisplayPickupSuggestionActivity; 33import com.android.settings.Settings.AmbientDisplaySuggestionActivity; 34import com.android.settings.Settings.DoubleTapPowerSuggestionActivity; 35import com.android.settings.Settings.DoubleTwistSuggestionActivity; 36import com.android.settings.Settings.NightDisplaySuggestionActivity; 37import com.android.settings.Settings.SwipeToNotificationSuggestionActivity; 38import com.android.settings.core.instrumentation.MetricsFeatureProvider; 39import com.android.settings.gestures.DoubleTapPowerPreferenceController; 40import com.android.settings.gestures.DoubleTapScreenPreferenceController; 41import com.android.settings.gestures.DoubleTwistPreferenceController; 42import com.android.settings.gestures.PickupGesturePreferenceController; 43import com.android.settings.gestures.SwipeToNotificationPreferenceController; 44import com.android.settings.overlay.FeatureFactory; 45import com.android.settings.support.NewDeviceIntroSuggestionActivity; 46import com.android.settingslib.drawer.Tile; 47import com.android.settingslib.suggestions.SuggestionParser; 48 49import java.util.ArrayList; 50import java.util.List; 51 52public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider { 53 54 private static final String TAG = "SuggestionFeature"; 55 private static final int EXCLUSIVE_SUGGESTION_MAX_COUNT = 3; 56 57 private static final String SHARED_PREF_FILENAME = "suggestions"; 58 59 private final SuggestionRanker mSuggestionRanker; 60 private final MetricsFeatureProvider mMetricsFeatureProvider; 61 62 @Override 63 public boolean isSuggestionEnabled(Context context) { 64 final ActivityManager am = 65 (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 66 return !am.isLowRamDevice(); 67 } 68 69 @Override 70 public boolean isSmartSuggestionEnabled(Context context) { 71 return false; 72 } 73 74 @Override 75 public boolean isSuggestionCompleted(Context context, @NonNull ComponentName component) { 76 final String className = component.getClassName(); 77 if (className.equals(NightDisplaySuggestionActivity.class.getName())) { 78 return hasUsedNightDisplay(context); 79 } 80 if (className.equals(NewDeviceIntroSuggestionActivity.class.getName())) { 81 return NewDeviceIntroSuggestionActivity.isSuggestionComplete(context); 82 } else if (className.equals(DoubleTapPowerSuggestionActivity.class.getName())) { 83 return DoubleTapPowerPreferenceController 84 .isSuggestionComplete(context, getSharedPrefs(context)); 85 } else if (className.equals(DoubleTwistSuggestionActivity.class.getName())) { 86 return DoubleTwistPreferenceController 87 .isSuggestionComplete(context, getSharedPrefs(context)); 88 } else if (className.equals(AmbientDisplaySuggestionActivity.class.getName())) { 89 return DoubleTapScreenPreferenceController 90 .isSuggestionComplete(context, getSharedPrefs(context)); 91 } else if (className.equals(AmbientDisplayPickupSuggestionActivity.class.getName())) { 92 return PickupGesturePreferenceController 93 .isSuggestionComplete(context, getSharedPrefs(context)); 94 } else if (className.equals(SwipeToNotificationSuggestionActivity.class.getName())) { 95 return SwipeToNotificationPreferenceController 96 .isSuggestionComplete(context, getSharedPrefs(context)); 97 } 98 return false; 99 } 100 101 @Override 102 public SharedPreferences getSharedPrefs(Context context) { 103 return context.getSharedPreferences(SHARED_PREF_FILENAME, Context.MODE_PRIVATE); 104 } 105 106 public SuggestionFeatureProviderImpl(Context context) { 107 final Context appContext = context.getApplicationContext(); 108 mSuggestionRanker = new SuggestionRanker( 109 new SuggestionFeaturizer(new EventStore(appContext))); 110 mMetricsFeatureProvider = FeatureFactory.getFactory(appContext) 111 .getMetricsFeatureProvider(); 112 } 113 114 @Override 115 public void rankSuggestions(final List<Tile> suggestions, List<String> suggestionIds) { 116 mSuggestionRanker.rankSuggestions(suggestions, suggestionIds); 117 } 118 119 @Override 120 public void filterExclusiveSuggestions(List<Tile> suggestions) { 121 if (suggestions == null) { 122 return; 123 } 124 for (int i = suggestions.size() - 1; i >= EXCLUSIVE_SUGGESTION_MAX_COUNT; i--) { 125 Log.d(TAG, "Removing exclusive suggestion"); 126 suggestions.remove(i); 127 } 128 } 129 130 @Override 131 public void dismissSuggestion(Context context, SuggestionParser parser, Tile suggestion) { 132 if (parser == null || suggestion == null || context == null) { 133 return; 134 } 135 final Pair<Integer, Object>[] taggedData = 136 SuggestionLogHelper.getSuggestionTaggedData(isSmartSuggestionEnabled(context)); 137 138 mMetricsFeatureProvider.action( 139 context, MetricsEvent.ACTION_SETTINGS_DISMISS_SUGGESTION, 140 getSuggestionIdentifier(context, suggestion), 141 taggedData); 142 if (!parser.dismissSuggestion(suggestion)) { 143 return; 144 } 145 context.getPackageManager().setComponentEnabledSetting( 146 suggestion.intent.getComponent(), 147 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 148 PackageManager.DONT_KILL_APP); 149 } 150 151 @Override 152 public String getSuggestionIdentifier(Context context, Tile suggestion) { 153 if (suggestion.intent == null || suggestion.intent.getComponent() == null 154 || context == null) { 155 return "unknown_suggestion"; 156 } 157 String packageName = suggestion.intent.getComponent().getPackageName(); 158 if (packageName.equals(context.getPackageName())) { 159 // Since Settings provides several suggestions, fill in the class instead of the 160 // package for these. 161 packageName = suggestion.intent.getComponent().getClassName(); 162 } 163 return packageName; 164 } 165 166 @VisibleForTesting 167 boolean hasUsedNightDisplay(Context context) { 168 final ContentResolver cr = context.getContentResolver(); 169 return Secure.getInt(cr, Secure.NIGHT_DISPLAY_AUTO_MODE, 0) != 0 170 || Secure.getString(cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME) != null; 171 } 172} 173