1 /* 2 * Copyright (C) 2022 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.settings.dream; 18 19 import android.app.settings.SettingsEnums; 20 import android.content.Context; 21 import android.graphics.drawable.Drawable; 22 23 import androidx.annotation.Nullable; 24 import androidx.preference.Preference; 25 import androidx.preference.PreferenceScreen; 26 import androidx.recyclerview.widget.RecyclerView; 27 28 import com.android.settings.R; 29 import com.android.settings.core.BasePreferenceController; 30 import com.android.settings.overlay.FeatureFactory; 31 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 32 import com.android.settingslib.dream.DreamBackend; 33 import com.android.settingslib.dream.DreamBackend.DreamInfo; 34 import com.android.settingslib.widget.LayoutPreference; 35 36 import java.util.HashSet; 37 import java.util.List; 38 import java.util.stream.Collectors; 39 40 /** 41 * Controller for the dream picker where the user can select a screensaver. 42 */ 43 public class DreamPickerController extends BasePreferenceController { 44 public static final String PREF_KEY = "dream_picker"; 45 46 private final DreamBackend mBackend; 47 private final MetricsFeatureProvider mMetricsFeatureProvider; 48 private final List<DreamInfo> mDreamInfos; 49 @Nullable 50 private DreamInfo mActiveDream; 51 private DreamAdapter mAdapter; 52 53 private final HashSet<Callback> mCallbacks = new HashSet<>(); 54 DreamPickerController(Context context)55 public DreamPickerController(Context context) { 56 this(context, DreamBackend.getInstance(context)); 57 } 58 DreamPickerController(Context context, DreamBackend backend)59 public DreamPickerController(Context context, DreamBackend backend) { 60 super(context, PREF_KEY); 61 mBackend = backend; 62 mDreamInfos = mBackend.getDreamInfos(); 63 mActiveDream = getActiveDreamInfo(mDreamInfos); 64 mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); 65 } 66 67 @Override getAvailabilityStatus()68 public int getAvailabilityStatus() { 69 return mDreamInfos.size() > 0 ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; 70 } 71 72 @Override displayPreference(PreferenceScreen screen)73 public void displayPreference(PreferenceScreen screen) { 74 super.displayPreference(screen); 75 76 mAdapter = new DreamAdapter(R.layout.dream_preference_layout, 77 mDreamInfos.stream() 78 .map(DreamItem::new) 79 .collect(Collectors.toList())); 80 81 mAdapter.setEnabled(mBackend.isEnabled()); 82 83 final LayoutPreference pref = screen.findPreference(getPreferenceKey()); 84 if (pref == null) { 85 return; 86 } 87 final RecyclerView recyclerView = pref.findViewById(R.id.dream_list); 88 recyclerView.setLayoutManager(new AutoFitGridLayoutManager(mContext)); 89 recyclerView.addItemDecoration( 90 new GridSpacingItemDecoration(mContext, R.dimen.dream_preference_card_padding)); 91 recyclerView.setHasFixedSize(true); 92 recyclerView.setAdapter(mAdapter); 93 } 94 95 @Override updateState(Preference preference)96 public void updateState(Preference preference) { 97 super.updateState(preference); 98 if (mAdapter != null) { 99 mAdapter.setEnabled(preference.isEnabled()); 100 } 101 } 102 103 @Nullable getActiveDreamInfo()104 public DreamInfo getActiveDreamInfo() { 105 return mActiveDream; 106 } 107 108 @Nullable getActiveDreamInfo(List<DreamInfo> dreamInfos)109 private static DreamInfo getActiveDreamInfo(List<DreamInfo> dreamInfos) { 110 return dreamInfos 111 .stream() 112 .filter(d -> d.isActive) 113 .findFirst() 114 .orElse(null); 115 } 116 addCallback(Callback callback)117 void addCallback(Callback callback) { 118 mCallbacks.add(callback); 119 } 120 removeCallback(Callback callback)121 void removeCallback(Callback callback) { 122 mCallbacks.remove(callback); 123 } 124 125 interface Callback { 126 // Triggered when the selected dream changes. onActiveDreamChanged()127 void onActiveDreamChanged(); 128 } 129 130 private class DreamItem implements IDreamItem { 131 DreamInfo mDreamInfo; 132 DreamItem(DreamInfo dreamInfo)133 DreamItem(DreamInfo dreamInfo) { 134 mDreamInfo = dreamInfo; 135 } 136 137 @Override getTitle()138 public CharSequence getTitle() { 139 return mDreamInfo.caption; 140 } 141 142 @Override getSummary()143 public CharSequence getSummary() { 144 return mDreamInfo.description; 145 } 146 147 @Override getIcon()148 public Drawable getIcon() { 149 return mDreamInfo.icon; 150 } 151 152 @Override onItemClicked()153 public void onItemClicked() { 154 mActiveDream = mDreamInfo; 155 mBackend.setActiveDream(mDreamInfo.componentName); 156 mCallbacks.forEach(Callback::onActiveDreamChanged); 157 mMetricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN, 158 SettingsEnums.ACTION_DREAM_SELECT_TYPE, SettingsEnums.DREAM, 159 mDreamInfo.componentName.flattenToString(), 1); 160 } 161 162 @Override onCustomizeClicked()163 public void onCustomizeClicked() { 164 mBackend.launchSettings(mContext, mDreamInfo); 165 } 166 167 @Override getPreviewImage()168 public Drawable getPreviewImage() { 169 return mDreamInfo.previewImage; 170 } 171 172 @Override isActive()173 public boolean isActive() { 174 if (!mAdapter.getEnabled() || mActiveDream == null) { 175 return false; 176 } 177 return mDreamInfo.componentName.equals(mActiveDream.componentName); 178 } 179 180 @Override allowCustomization()181 public boolean allowCustomization() { 182 return isActive() && mDreamInfo.settingsComponentName != null; 183 } 184 } 185 } 186