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 package com.android.wallpaper.picker.individual;
17 
18 import android.app.Activity;
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.res.Resources.NotFoundException;
22 import android.graphics.Insets;
23 import android.os.Bundle;
24 import android.util.Log;
25 import android.view.MenuItem;
26 import android.view.View;
27 import android.view.WindowInsets;
28 import android.widget.Toast;
29 
30 import androidx.appcompat.widget.Toolbar;
31 import androidx.fragment.app.Fragment;
32 import androidx.fragment.app.FragmentManager;
33 
34 import com.android.wallpaper.R;
35 import com.android.wallpaper.compat.BuildCompat;
36 import com.android.wallpaper.model.Category;
37 import com.android.wallpaper.model.CategoryProvider;
38 import com.android.wallpaper.model.CategoryReceiver;
39 import com.android.wallpaper.model.InlinePreviewIntentFactory;
40 import com.android.wallpaper.model.LiveWallpaperInfo;
41 import com.android.wallpaper.model.PickerIntentFactory;
42 import com.android.wallpaper.model.WallpaperInfo;
43 import com.android.wallpaper.module.Injector;
44 import com.android.wallpaper.module.InjectorProvider;
45 import com.android.wallpaper.module.WallpaperPersister;
46 import com.android.wallpaper.picker.BaseActivity;
47 import com.android.wallpaper.picker.PreviewActivity.PreviewActivityIntentFactory;
48 import com.android.wallpaper.util.DiskBasedLogger;
49 
50 /**
51  * Activity that can be launched from the Android wallpaper picker and allows users to pick from
52  * various wallpapers and enter a preview mode for specific ones.
53  */
54 public class IndividualPickerActivity extends BaseActivity {
55     private static final String TAG = "IndividualPickerAct";
56     private static final String EXTRA_CATEGORY_COLLECTION_ID =
57             "com.android.wallpaper.category_collection_id";
58     private static final int PREVIEW_WALLPAPER_REQUEST_CODE = 0;
59     private static final int PREVIEW_LIVEWALLPAPER_REQUEST_CODE = 2;
60     private static final String KEY_CATEGORY_COLLECTION_ID = "key_category_collection_id";
61 
62     private InlinePreviewIntentFactory mPreviewIntentFactory;
63     private WallpaperPersister mWallpaperPersister;
64     private Category mCategory;
65     private String mCategoryCollectionId;
66 
67     @Override
onCreate(Bundle savedInstanceState)68     protected void onCreate(Bundle savedInstanceState) {
69         super.onCreate(savedInstanceState);
70         setContentView(R.layout.activity_single_fragment_with_toolbar);
71 
72         // Set toolbar as the action bar.
73         Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
74         setSupportActionBar(toolbar);
75 
76         mPreviewIntentFactory = new PreviewActivityIntentFactory();
77         Injector injector = InjectorProvider.getInjector();
78         mWallpaperPersister = injector.getWallpaperPersister(this);
79 
80         FragmentManager fm = getSupportFragmentManager();
81         Fragment fragment = fm.findFragmentById(R.id.fragment_container);
82 
83         mCategoryCollectionId = (savedInstanceState == null)
84                 ? getIntent().getStringExtra(EXTRA_CATEGORY_COLLECTION_ID)
85                 : savedInstanceState.getString(KEY_CATEGORY_COLLECTION_ID);
86         CategoryProvider categoryProvider = injector.getCategoryProvider(this);
87         categoryProvider.fetchCategories(new CategoryReceiver() {
88             @Override
89             public void onCategoryReceived(Category category) {
90                 // Do nothing.
91             }
92 
93             @Override
94             public void doneFetchingCategories() {
95                 mCategory = categoryProvider.getCategory(mCategoryCollectionId);
96                 if (mCategory == null) {
97                     DiskBasedLogger.e(TAG, "Failed to find the category: " + mCategoryCollectionId,
98                             IndividualPickerActivity.this);
99                     // We either were called with an invalid collection Id, or we're restarting with
100                     // no saved state, or with a collection id that doesn't exist anymore.
101                     // In those cases, we cannot continue, so let's just go back.
102                     finish();
103                     return;
104                 }
105                 onCategoryLoaded();
106             }
107         }, false);
108 
109         getSupportActionBar().setDisplayHomeAsUpEnabled(true);
110 
111         toolbar.getNavigationIcon().setTint(getColor(R.color.toolbar_icon_color));
112         toolbar.getNavigationIcon().setAutoMirrored(true);
113 
114         getWindow().getDecorView().setSystemUiVisibility(
115                 getWindow().getDecorView().getSystemUiVisibility()
116                         | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
117                         | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
118         ((View) findViewById(R.id.fragment_container).getParent())
119                 .setOnApplyWindowInsetsListener((view, windowInsets) -> {
120             view.setPadding(view.getPaddingLeft(), windowInsets.getSystemWindowInsetTop(),
121                     view.getPaddingRight(), view.getBottom());
122             // Consume only the top inset (status bar), to let other content in the Activity consume
123             // the nav bar (ie, by using "fitSystemWindows")
124             if (BuildCompat.isAtLeastQ()) {
125                 WindowInsets.Builder builder = new WindowInsets.Builder(windowInsets);
126                 builder.setSystemWindowInsets(Insets.of(windowInsets.getSystemWindowInsetLeft(),
127                         0, windowInsets.getStableInsetRight(),
128                         windowInsets.getSystemWindowInsetBottom()));
129                 return builder.build();
130             } else {
131                 return windowInsets.replaceSystemWindowInsets(
132                         windowInsets.getSystemWindowInsetLeft(),
133                         0, windowInsets.getStableInsetRight(),
134                         windowInsets.getSystemWindowInsetBottom());
135             }
136         });
137 
138         if (fragment == null) {
139             fragment = injector.getIndividualPickerFragment(mCategoryCollectionId);
140             fm.beginTransaction()
141                     .add(R.id.fragment_container, fragment)
142                     .commit();
143         }
144     }
145 
onCategoryLoaded()146     private void onCategoryLoaded() {
147         setTitle(mCategory.getTitle());
148         getSupportActionBar().setTitle(mCategory.getTitle());
149     }
150 
151     @Override
onOptionsItemSelected(MenuItem item)152     public boolean onOptionsItemSelected(MenuItem item) {
153         int id = item.getItemId();
154         if (id == android.R.id.home) {
155             // Handle Up as a Global back since the only entry point to IndividualPickerActivity is
156             // from TopLevelPickerActivity.
157             onBackPressed();
158             return true;
159         }
160         return false;
161     }
162 
163     @Override
onActivityResult(int requestCode, int resultCode, Intent data)164     public void onActivityResult(int requestCode, int resultCode, Intent data) {
165         super.onActivityResult(requestCode, resultCode, data);
166 
167         boolean shouldShowMessage = false;
168         switch (requestCode) {
169             case PREVIEW_LIVEWALLPAPER_REQUEST_CODE:
170                 shouldShowMessage = true;
171             case PREVIEW_WALLPAPER_REQUEST_CODE:
172                 if (resultCode == Activity.RESULT_OK) {
173                     mWallpaperPersister.onLiveWallpaperSet();
174 
175                     // The wallpaper was set, so finish this activity with result OK.
176                     finishWithResultOk(shouldShowMessage);
177                 }
178                 break;
179             default:
180                 Log.e(TAG, "Invalid request code: " + requestCode);
181         }
182     }
183 
184     /**
185      * Shows the preview activity for the given wallpaper.
186      */
showPreview(WallpaperInfo wallpaperInfo)187     public void showPreview(WallpaperInfo wallpaperInfo) {
188         mWallpaperPersister.setWallpaperInfoInPreview(wallpaperInfo);
189         wallpaperInfo.showPreview(this, mPreviewIntentFactory,
190                 wallpaperInfo instanceof LiveWallpaperInfo ? PREVIEW_LIVEWALLPAPER_REQUEST_CODE
191                         : PREVIEW_WALLPAPER_REQUEST_CODE);
192     }
193 
finishWithResultOk(boolean shouldShowMessage)194     private void finishWithResultOk(boolean shouldShowMessage) {
195         if (shouldShowMessage) {
196             try {
197                 Toast.makeText(this, R.string.wallpaper_set_successfully_message,
198                         Toast.LENGTH_SHORT).show();
199             } catch (NotFoundException e) {
200                 Log.e(TAG, "Could not show toast " + e);
201             }
202         }
203         overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
204         setResult(Activity.RESULT_OK);
205         finish();
206     }
207 
208     @Override
onSaveInstanceState(Bundle bundle)209     protected void onSaveInstanceState(Bundle bundle) {
210         super.onSaveInstanceState(bundle);
211 
212         bundle.putString(KEY_CATEGORY_COLLECTION_ID, mCategoryCollectionId);
213     }
214 
215     /**
216      * Default implementation of intent factory that provides an intent to start an
217      * IndividualPickerActivity.
218      */
219     public static class IndividualPickerActivityIntentFactory implements PickerIntentFactory {
220         @Override
newIntent(Context ctx, String collectionId)221         public Intent newIntent(Context ctx, String collectionId) {
222             return new Intent(ctx, IndividualPickerActivity.class).putExtra(
223                     EXTRA_CATEGORY_COLLECTION_ID, collectionId);
224         }
225     }
226 }
227