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