Extract TopLevelPickerActivity's logic

Moved all the Wallpaper related logic in TopLevelPickerActivity
(except for desktop-specific), to a delegate, so it can be
reused by ThemePicker.

Bug: 120560581
Change-Id: I15d24fa599a00ebea241ee142584b0ac45276648
diff --git a/src/com/android/wallpaper/picker/WallpaperPickerDelegate.java b/src/com/android/wallpaper/picker/WallpaperPickerDelegate.java
new file mode 100644
index 0000000..0cca494
--- /dev/null
+++ b/src/com/android/wallpaper/picker/WallpaperPickerDelegate.java
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wallpaper.picker;
+
+import android.Manifest.permission;
+import android.app.WallpaperManager;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.service.wallpaper.WallpaperService;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.wallpaper.R;
+import com.android.wallpaper.compat.WallpaperManagerCompat;
+import com.android.wallpaper.model.Category;
+import com.android.wallpaper.model.CategoryProvider;
+import com.android.wallpaper.model.CategoryReceiver;
+import com.android.wallpaper.model.InlinePreviewIntentFactory;
+import com.android.wallpaper.model.WallpaperInfo;
+import com.android.wallpaper.module.FormFactorChecker;
+import com.android.wallpaper.module.FormFactorChecker.FormFactor;
+import com.android.wallpaper.module.Injector;
+import com.android.wallpaper.module.InjectorProvider;
+import com.android.wallpaper.module.PackageStatusNotifier;
+import com.android.wallpaper.module.PackageStatusNotifier.PackageStatus;
+import com.android.wallpaper.module.WallpaperPreferences;
+import com.android.wallpaper.picker.PreviewActivity.PreviewActivityIntentFactory;
+import com.android.wallpaper.picker.ViewOnlyPreviewActivity.ViewOnlyPreviewActivityIntentFactory;
+import com.android.wallpaper.picker.WallpaperDisabledFragment.WallpaperSupportLevel;
+import com.android.wallpaper.picker.individual.IndividualPickerActivity.IndividualPickerActivityIntentFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implements all the logic for handling a WallpaperPicker container Activity.
+ * @see TopLevelPickerActivity for usage details.
+ */
+public class WallpaperPickerDelegate implements MyPhotosLauncher {
+
+    private final BaseActivity mActivity;
+    private final WallpapersUiContainer mContainer;
+    static final int SHOW_CATEGORY_REQUEST_CODE = 0;
+    static final int PREVIEW_WALLPAPER_REQUEST_CODE = 1;
+    static final int VIEW_ONLY_PREVIEW_WALLPAPER_REQUEST_CODE = 2;
+    static final int READ_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE = 3;
+
+    private IndividualPickerActivityIntentFactory mPickerIntentFactory;
+
+    private InlinePreviewIntentFactory mPreviewIntentFactory;
+    private InlinePreviewIntentFactory mViewOnlyPreviewIntentFactory;
+
+    @FormFactor private int mFormFactor;
+    private WallpaperPreferences mPreferences;
+    private PackageStatusNotifier mPackageStatusNotifier;
+
+    private List<PermissionChangedListener> mPermissionChangedListeners;
+    private PackageStatusNotifier.Listener mLiveWallpaperStatusListener;
+    private PackageStatusNotifier.Listener mThirdPartyStatusListener;
+    private CategoryProvider mCategoryProvider;
+
+    public WallpaperPickerDelegate(WallpapersUiContainer container, BaseActivity activity,
+            Injector injector) {
+        mContainer = container;
+        mActivity = activity;
+        mPickerIntentFactory = new IndividualPickerActivityIntentFactory();
+        mPreviewIntentFactory = new PreviewActivityIntentFactory();
+        mViewOnlyPreviewIntentFactory =
+                new ViewOnlyPreviewActivityIntentFactory();
+
+        mCategoryProvider = injector.getCategoryProvider(activity);
+        mPreferences = injector.getPreferences(activity);
+
+        mPackageStatusNotifier = injector.getPackageStatusNotifier(activity);
+        final FormFactorChecker formFactorChecker = injector.getFormFactorChecker(activity);
+        mFormFactor = formFactorChecker.getFormFactor();
+
+        mPermissionChangedListeners = new ArrayList<>();
+    }
+
+    public void initialize(boolean forceCategoryRefresh) {
+        populateCategories(forceCategoryRefresh);
+        mLiveWallpaperStatusListener = this::updateLiveWallpapersCategories;
+        mThirdPartyStatusListener = this::updateThirdPartyCategories;
+        mPackageStatusNotifier.addListener(
+                mLiveWallpaperStatusListener,
+                WallpaperService.SERVICE_INTERFACE);
+        mPackageStatusNotifier.addListener(mThirdPartyStatusListener, Intent.ACTION_SET_WALLPAPER);
+    }
+
+    @Override
+    public void requestCustomPhotoPicker(PermissionChangedListener listener) {
+        if (!isReadExternalStoragePermissionGranted()) {
+            PermissionChangedListener wrappedListener = new PermissionChangedListener() {
+                @Override
+                public void onPermissionsGranted() {
+                    listener.onPermissionsGranted();
+                    showCustomPhotoPicker();
+                }
+
+                @Override
+                public void onPermissionsDenied(boolean dontAskAgain) {
+                    listener.onPermissionsDenied(dontAskAgain);
+                }
+            };
+            requestExternalStoragePermission(wrappedListener);
+
+            return;
+        }
+
+        showCustomPhotoPicker();
+    }
+
+    /**
+     * Requests to show the Android custom photo picker for the sake of picking a
+     * photo to set as the device's wallpaper.
+     */
+    public void requestExternalStoragePermission(PermissionChangedListener listener) {
+        mPermissionChangedListeners.add(listener);
+        mActivity.requestPermissions(
+                new String[]{permission.READ_EXTERNAL_STORAGE},
+                READ_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
+    }
+
+    /**
+     * Returns whether READ_EXTERNAL_STORAGE has been granted for the application.
+     */
+    public boolean isReadExternalStoragePermissionGranted() {
+        return mActivity.getPackageManager().checkPermission(
+                permission.READ_EXTERNAL_STORAGE,
+                mActivity.getPackageName()) == PackageManager.PERMISSION_GRANTED;
+    }
+
+    private void showCustomPhotoPicker() {
+        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+        intent.setType("image/*");
+        mActivity.startActivityForResult(intent, SHOW_CATEGORY_REQUEST_CODE);
+    }
+
+    private void updateThirdPartyCategories(String packageName, @PackageStatus int status) {
+        if (status == PackageStatus.ADDED) {
+            mCategoryProvider.fetchCategories(new CategoryReceiver() {
+                @Override
+                public void onCategoryReceived(Category category) {
+                    if (category.supportsThirdParty() && category.containsThirdParty(packageName)) {
+                        addCategory(category, false);
+                    }
+                }
+
+                @Override
+                public void doneFetchingCategories() {
+                    // Do nothing here.
+                }
+            }, true);
+        } else if (status == PackageStatus.REMOVED) {
+            Category oldCategory = findThirdPartyCategory(packageName);
+            if (oldCategory != null) {
+                mCategoryProvider.fetchCategories(new CategoryReceiver() {
+                    @Override
+                    public void onCategoryReceived(Category category) {
+                        // Do nothing here
+                    }
+
+                    @Override
+                    public void doneFetchingCategories() {
+                        removeCategory(oldCategory);
+                    }
+                }, true);
+            }
+        } else {
+            // CHANGED package, let's reload all categories as we could have more or fewer now
+            populateCategories(true);
+        }
+    }
+
+    private Category findThirdPartyCategory(String packageName) {
+        int size = mCategoryProvider.getSize();
+        for (int i = 0; i < size; i++) {
+            Category category = mCategoryProvider.getCategory(i);
+            if (category.supportsThirdParty() && category.containsThirdParty(packageName)) {
+                return category;
+            }
+        }
+        return null;
+    }
+
+    private void updateLiveWallpapersCategories(String packageName,
+            @PackageStatus int status) {
+        String liveWallpaperCollectionId = mActivity.getString(
+                R.string.live_wallpaper_collection_id);
+        Category oldLiveWallpapersCategory = mCategoryProvider.getCategory(
+                liveWallpaperCollectionId);
+        if (status == PackageStatus.REMOVED
+                && (oldLiveWallpapersCategory == null
+                || !oldLiveWallpapersCategory.containsThirdParty(packageName))) {
+            // If we're removing a wallpaper and the live category didn't contain it already,
+            // there's nothing to do.
+            return;
+        }
+        mCategoryProvider.fetchCategories(new CategoryReceiver() {
+            @Override
+            public void onCategoryReceived(Category category) {
+                // Do nothing here
+            }
+
+            @Override
+            public void doneFetchingCategories() {
+                Category liveWallpapersCategory =
+                        mCategoryProvider.getCategory(liveWallpaperCollectionId);
+                if (liveWallpapersCategory == null) {
+                    // There are no more 3rd party live wallpapers, so the Category is gone.
+                    removeCategory(oldLiveWallpapersCategory);
+                } else {
+                    if (oldLiveWallpapersCategory != null) {
+                        updateCategory(liveWallpapersCategory);
+                    } else {
+                        addCategory(liveWallpapersCategory, false);
+                    }
+                }
+            }
+        }, true);
+    }
+
+    /**
+     * Populates the categories appropriately depending on the device form factor.
+     *
+     * @param forceRefresh        Whether to force a refresh of categories from the
+     *                            CategoryProvider. True if
+     *                            on first launch.
+     */
+    public void populateCategories(boolean forceRefresh) {
+
+        final CategoryFragment categoryFragment = getCategoryPickerFragment();
+
+        if (forceRefresh && categoryFragment != null) {
+            categoryFragment.clearCategories();
+        }
+
+        mCategoryProvider.fetchCategories(new CategoryReceiver() {
+            @Override
+            public void onCategoryReceived(Category category) {
+                addCategory(category, true);
+            }
+
+            @Override
+            public void doneFetchingCategories() {
+                notifyDoneFetchingCategories();
+            }
+        }, forceRefresh);
+    }
+
+    private void notifyDoneFetchingCategories() {
+        if (mFormFactor == FormFactorChecker.FORM_FACTOR_MOBILE) {
+            CategoryFragment categoryFragment = getCategoryPickerFragment();
+            if (categoryFragment != null) {
+                categoryFragment.doneFetchingCategories();
+            }
+        } else {
+            mContainer.doneFetchingCategories();
+        }
+    }
+
+    public void addCategory(Category category, boolean fetchingAll) {
+        CategoryFragment categoryFragment = getCategoryPickerFragment();
+        if (categoryFragment != null) {
+            categoryFragment.addCategory(category, fetchingAll);
+        }
+    }
+
+    public void removeCategory(Category category) {
+        CategoryFragment categoryFragment = getCategoryPickerFragment();
+        if (categoryFragment != null) {
+            categoryFragment.removeCategory(category);
+        }
+    }
+
+    public void updateCategory(Category category) {
+        CategoryFragment categoryFragment = getCategoryPickerFragment();
+        if (categoryFragment != null) {
+            categoryFragment.updateCategory(category);
+        }
+    }
+
+    @Nullable
+    private CategoryFragment getCategoryPickerFragment() {
+        return mContainer.getCategoryFragment();
+    }
+
+    /**
+     * Shows the view-only preview activity for the given wallpaper.
+     */
+    public void showViewOnlyPreview(WallpaperInfo wallpaperInfo) {
+        wallpaperInfo.showPreview(
+                mActivity, mViewOnlyPreviewIntentFactory,
+                VIEW_ONLY_PREVIEW_WALLPAPER_REQUEST_CODE);
+    }
+
+    /**
+     * Shows the picker activity for the given category.
+     */
+    public void show(String collectionId) {
+        Category category = findCategoryForCollectionId(collectionId);
+        if (category == null) {
+            return;
+        }
+        category.show(mActivity, mPickerIntentFactory, SHOW_CATEGORY_REQUEST_CODE);
+    }
+
+    @Nullable
+    public Category findCategoryForCollectionId(String collectionId) {
+        return mCategoryProvider.getCategory(collectionId);
+    }
+
+    @WallpaperSupportLevel
+    public int getWallpaperSupportLevel() {
+        WallpaperManager wallpaperManager = WallpaperManager.getInstance(mActivity);
+
+        if (VERSION.SDK_INT >= VERSION_CODES.N) {
+            if (wallpaperManager.isWallpaperSupported()) {
+                return wallpaperManager.isSetWallpaperAllowed()
+                        ? WallpaperDisabledFragment.SUPPORTED_CAN_SET
+                        : WallpaperDisabledFragment.NOT_SUPPORTED_BLOCKED_BY_ADMIN;
+            }
+            return WallpaperDisabledFragment.NOT_SUPPORTED_BY_DEVICE;
+        } else if (VERSION.SDK_INT >= VERSION_CODES.M) {
+            return wallpaperManager.isWallpaperSupported()
+                    ? WallpaperDisabledFragment.SUPPORTED_CAN_SET
+                    : WallpaperDisabledFragment.NOT_SUPPORTED_BY_DEVICE;
+        } else {
+            WallpaperManagerCompat wallpaperManagerCompat =
+                    InjectorProvider.getInjector().getWallpaperManagerCompat(
+                            mActivity);
+            boolean isSupported = wallpaperManagerCompat.getDrawable() != null;
+            wallpaperManager.forgetLoadedWallpaper();
+            return isSupported ? WallpaperDisabledFragment.SUPPORTED_CAN_SET
+                    : WallpaperDisabledFragment.NOT_SUPPORTED_BY_DEVICE;
+        }
+    }
+
+    public IndividualPickerActivityIntentFactory getPickerIntentFactory() {
+        return mPickerIntentFactory;
+    }
+
+    public InlinePreviewIntentFactory getPreviewIntentFactory() {
+        return mPreviewIntentFactory;
+    }
+
+    @FormFactor
+    public int getFormFactor() {
+        return mFormFactor;
+    }
+
+    public WallpaperPreferences getPreferences() {
+        return mPreferences;
+    }
+
+    public List<PermissionChangedListener> getPermissionChangedListeners() {
+        return mPermissionChangedListeners;
+    }
+
+    public CategoryProvider getCategoryProvider() {
+        return mCategoryProvider;
+    }
+
+    /**
+     * Call when the owner activity is destroyed to clean up listeners.
+     */
+    public void cleanUp() {
+        if (mPackageStatusNotifier != null) {
+            mPackageStatusNotifier.removeListener(mLiveWallpaperStatusListener);
+            mPackageStatusNotifier.removeListener(mThirdPartyStatusListener);
+        }
+    }
+
+    /**
+     * Call from the Activity's onRequestPermissionsResult callback to handle permission request
+     * relevant to wallpapers (ie, READ_EXTERNAL_STORAGE)
+     * @see androidx.fragment.app.FragmentActivity#onRequestPermissionsResult(int, String[], int[])
+     */
+    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+            @NonNull int[] grantResults) {
+        if (requestCode == WallpaperPickerDelegate.READ_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE
+                && permissions.length > 0
+                && permissions[0].equals(permission.READ_EXTERNAL_STORAGE)
+                && grantResults.length > 0) {
+            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+                for (PermissionChangedListener listener : getPermissionChangedListeners()) {
+                    listener.onPermissionsGranted();
+                }
+            } else if (!mActivity.shouldShowRequestPermissionRationale(
+                    permission.READ_EXTERNAL_STORAGE)) {
+                for (PermissionChangedListener listener : getPermissionChangedListeners()) {
+                    listener.onPermissionsDenied(true /* dontAskAgain */);
+                }
+            } else {
+                for (PermissionChangedListener listener :getPermissionChangedListeners()) {
+                    listener.onPermissionsDenied(false /* dontAskAgain */);
+                }
+            }
+        }
+       getPermissionChangedListeners().clear();
+    }
+}
\ No newline at end of file