1 /* 2 * Copyright (C) 2019 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 package com.android.customization.model.grid; 17 18 import android.content.Context; 19 import android.os.Handler; 20 import android.os.Looper; 21 import android.util.Log; 22 23 import androidx.annotation.Nullable; 24 import androidx.annotation.VisibleForTesting; 25 import androidx.lifecycle.LiveData; 26 27 import com.android.customization.model.CustomizationManager; 28 import com.android.customization.module.CustomizationInjector; 29 import com.android.customization.module.logging.ThemesUserEventLogger; 30 import com.android.wallpaper.R; 31 import com.android.wallpaper.module.InjectorProvider; 32 33 import java.util.List; 34 import java.util.concurrent.ExecutionException; 35 import java.util.concurrent.ExecutorService; 36 import java.util.concurrent.Executors; 37 38 /** 39 * {@link CustomizationManager} for interfacing with the launcher to handle {@link GridOption}s. 40 */ 41 public class GridOptionsManager implements CustomizationManager<GridOption> { 42 43 private static final ExecutorService sExecutorService = Executors.newSingleThreadExecutor(); 44 private static final String TAG = "GridOptionsManager"; 45 46 private static GridOptionsManager sGridOptionsManager; 47 48 private final LauncherGridOptionsProvider mProvider; 49 private final ThemesUserEventLogger mEventLogger; 50 private int mGridOptionSize = -1; 51 52 /** Returns the {@link GridOptionsManager} instance. */ getInstance(Context context)53 public static GridOptionsManager getInstance(Context context) { 54 if (sGridOptionsManager == null) { 55 Context appContext = context.getApplicationContext(); 56 CustomizationInjector injector = (CustomizationInjector) InjectorProvider.getInjector(); 57 ThemesUserEventLogger eventLogger = 58 (ThemesUserEventLogger) injector.getUserEventLogger(); 59 sGridOptionsManager = new GridOptionsManager( 60 new LauncherGridOptionsProvider(appContext, 61 appContext.getString(R.string.grid_control_metadata_name)), 62 eventLogger); 63 } 64 return sGridOptionsManager; 65 } 66 67 @VisibleForTesting GridOptionsManager(LauncherGridOptionsProvider provider, ThemesUserEventLogger logger)68 GridOptionsManager(LauncherGridOptionsProvider provider, ThemesUserEventLogger logger) { 69 mProvider = provider; 70 mEventLogger = logger; 71 } 72 73 @Override isAvailable()74 public boolean isAvailable() { 75 if (mGridOptionSize < 0) { 76 try { 77 mGridOptionSize = sExecutorService.submit(() -> { 78 List<GridOption> gridOptions = mProvider.fetch(/* reload= */true); 79 return gridOptions == null ? 0 : gridOptions.size(); 80 }).get(); 81 } catch (InterruptedException | ExecutionException e) { 82 Log.w(TAG, "could not get gridOptionSize", e); 83 } 84 } 85 return mGridOptionSize > 1 && mProvider.areGridsAvailable(); 86 } 87 88 @Override apply(GridOption option, Callback callback)89 public void apply(GridOption option, Callback callback) { 90 int updated = mProvider.applyGrid(option.name); 91 if (updated == 1) { 92 mEventLogger.logGridApplied(option); 93 callback.onSuccess(); 94 } else { 95 callback.onError(null); 96 } 97 } 98 99 @Override preview(GridOption option)100 public void preview(GridOption option) { 101 mProvider.updateView(); 102 } 103 104 @Override fetchOptions(OptionsFetchedListener<GridOption> callback, boolean reload)105 public void fetchOptions(OptionsFetchedListener<GridOption> callback, boolean reload) { 106 sExecutorService.submit(() -> { 107 List<GridOption> gridOptions = mProvider.fetch(reload); 108 new Handler(Looper.getMainLooper()).post(() -> { 109 if (callback != null) { 110 if (gridOptions != null && !gridOptions.isEmpty()) { 111 callback.onOptionsLoaded(gridOptions); 112 } else { 113 callback.onError(null); 114 } 115 } 116 }); 117 }); 118 } 119 120 /** 121 * Returns an observable that receives a new value each time that the grid options are changed. 122 */ getOptionChangeObservable(@ullable Handler handler)123 public LiveData<Object> getOptionChangeObservable(@Nullable Handler handler) { 124 return mProvider.getOptionChangeObservable(handler); 125 } 126 } 127