1/*
2 * Copyright (C) 2014 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
17package com.example.android.supportv7.graphics;
18
19import android.content.Context;
20import android.content.Intent;
21import android.database.Cursor;
22import android.graphics.Bitmap;
23import android.net.Uri;
24import android.os.Bundle;
25import android.provider.MediaStore;
26import android.view.Menu;
27import android.view.MenuInflater;
28import android.view.MenuItem;
29import android.view.View;
30import android.widget.ImageView;
31import android.widget.ListView;
32
33import androidx.annotation.NonNull;
34import androidx.appcompat.app.AppCompatActivity;
35import androidx.core.view.ViewCompat;
36import androidx.cursoradapter.widget.ResourceCursorAdapter;
37import androidx.fragment.app.ListFragment;
38import androidx.loader.app.LoaderManager;
39import androidx.loader.content.CursorLoader;
40import androidx.loader.content.Loader;
41import androidx.palette.graphics.Palette;
42
43import com.example.android.supportv7.R;
44
45/**
46 * Activity which displays the images from the device's {@link MediaStore}, alongside the generated
47 * {@link androidx.palette.graphics.Palette} results.
48 *
49 * Allows the customization of the number of colors used in the palette generation, to demonstrate
50 * the difference in results for different types of images.
51 */
52public class PaletteActivity extends AppCompatActivity {
53
54    @Override
55    protected void onCreate(Bundle savedInstanceState) {
56        super.onCreate(savedInstanceState);
57
58        getSupportFragmentManager()
59                .beginTransaction()
60                .replace(android.R.id.content, new PaletteMediaStoreListFragment())
61                .commit();
62    }
63
64    /**
65     * The {@link androidx.fragment.app.ListFragment} which does all of the hard work.
66     */
67    public static class PaletteMediaStoreListFragment extends ListFragment
68            implements LoaderManager.LoaderCallbacks<Cursor> {
69
70        /**
71         * Projection used for querying the {@link android.provider.MediaStore}.
72         */
73        static final String[] PROJECTION = {
74                MediaStore.Images.ImageColumns._ID,
75                MediaStore.Images.ImageColumns.DATE_ADDED
76        };
77
78        private PhotosCursorAdapter mAdapter;
79
80        @Override
81        public void onCreate(Bundle savedInstanceState) {
82            super.onCreate(savedInstanceState);
83            setHasOptionsMenu(true);
84        }
85
86        @Override
87        public void onViewCreated(View view, Bundle savedInstanceState) {
88            super.onViewCreated(view, savedInstanceState);
89
90            // Enable fast scroll to make it easier to navigate large number of images
91            getListView().setFastScrollEnabled(true);
92        }
93
94        @Override
95        public void onActivityCreated(Bundle savedInstanceState) {
96            super.onActivityCreated(savedInstanceState);
97
98            // Create an Adapter and use a new Adapter
99            mAdapter = new PhotosCursorAdapter(getActivity(), null);
100            mAdapter.setNumColors(16);
101            setListAdapter(mAdapter);
102
103            // Start the loader manager to create our CursorLoader
104            getLoaderManager().initLoader(0, null, this);
105        }
106
107        @Override
108        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
109            inflater.inflate(R.menu.sample_palette_actions, menu);
110        }
111
112        @Override
113        public boolean onOptionsItemSelected(MenuItem item) {
114            switch (item.getItemId()) {
115                case R.id.menu_num_colors_8:
116                    mAdapter.setNumColors(8);
117                    item.setChecked(true);
118                    return true;
119                case R.id.menu_num_colors_12:
120                    mAdapter.setNumColors(12);
121                    item.setChecked(true);
122                    return true;
123                case R.id.menu_num_colors_16:
124                    mAdapter.setNumColors(16);
125                    item.setChecked(true);
126                    return true;
127                case R.id.menu_num_colors_24:
128                    mAdapter.setNumColors(24);
129                    item.setChecked(true);
130                    return true;
131                case R.id.menu_num_colors_32:
132                    mAdapter.setNumColors(32);
133                    item.setChecked(true);
134                    return true;
135            }
136
137            return super.onOptionsItemSelected(item);
138        }
139
140        @Override
141        public void onListItemClick(ListView l, View v, int position, long id) {
142            final Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon()
143                    .appendEncodedPath(String.valueOf(id)).build();
144
145            // Start the Detail Activity
146            Intent intent = new Intent(getActivity(), PaletteDetailActivity.class);
147            intent.setData(uri);
148            startActivity(intent);
149        }
150
151        @NonNull
152        @Override
153        public Loader<Cursor> onCreateLoader(int id, Bundle bundle) {
154            return new CursorLoader(
155                    getActivity(),
156                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
157                    PROJECTION,
158                    null,
159                    null,
160                    MediaStore.Images.ImageColumns.DATE_ADDED + " DESC");
161        }
162
163        @Override
164        public void onLoadFinished(@NonNull Loader<Cursor> cursorLoader, Cursor cursor) {
165            mAdapter.swapCursor(cursor);
166        }
167
168        @Override
169        public void onLoaderReset(@NonNull Loader<Cursor> cursorLoader) {
170            mAdapter.swapCursor(null);
171        }
172
173        private static class PhotosCursorAdapter extends ResourceCursorAdapter {
174
175            private int mNumColors;
176
177            public PhotosCursorAdapter(Context context, Cursor c) {
178                super(context, R.layout.palette_list_item, c, false);
179                mContext = context;
180            }
181
182            /**
183             * Set the number of colors used for {@link Palette} generation.
184             */
185            void setNumColors(int numColors) {
186                mNumColors = numColors;
187                notifyDataSetChanged();
188            }
189
190            @Override
191            public void bindView(final View view, Context context, Cursor cursor) {
192                // Let's reset the view, clearing the ImageView and resetting the background colors
193                // of the Palette UI
194                ImageView imageView = (ImageView) view.findViewById(R.id.image);
195                imageView.setImageDrawable(null);
196
197                ViewCompat.setBackground(view.findViewById(R.id.text_vibrant), null);
198                ViewCompat.setBackground(view.findViewById(R.id.text_muted), null);
199                ViewCompat.setBackground(view.findViewById(R.id.text_light_vibrant), null);
200                ViewCompat.setBackground(view.findViewById(R.id.text_light_muted), null);
201                ViewCompat.setBackground(view.findViewById(R.id.text_dark_vibrant), null);
202                ViewCompat.setBackground(view.findViewById(R.id.text_dark_muted), null);
203
204                final long id = cursor.getLong(
205                        cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns._ID));
206
207                ImageLoader.loadMediaStoreThumbnail(imageView, id, new ImageLoader.Listener() {
208                    @Override
209                    public void onImageLoaded(Bitmap bitmap) {
210                        new Palette.Builder(bitmap).maximumColorCount(mNumColors).generate(
211                                new Palette.PaletteAsyncListener() {
212                                    @Override
213                                    public void onGenerated(Palette palette) {
214                                        setBackgroundColor(
215                                                view.findViewById(R.id.text_vibrant),
216                                                palette.getVibrantSwatch());
217                                        setBackgroundColor(
218                                                view.findViewById(R.id.text_muted),
219                                                palette.getMutedSwatch());
220                                        setBackgroundColor(
221                                                view.findViewById(R.id.text_light_vibrant),
222                                                palette.getLightVibrantSwatch());
223                                        setBackgroundColor(
224                                                view.findViewById(R.id.text_light_muted),
225                                                palette.getLightMutedSwatch());
226                                        setBackgroundColor(
227                                                view.findViewById(R.id.text_dark_vibrant),
228                                                palette.getDarkVibrantSwatch());
229                                        setBackgroundColor(
230                                                view.findViewById(R.id.text_dark_muted),
231                                                palette.getDarkMutedSwatch());
232                                    }
233                                });
234                    }
235                });
236            }
237        }
238
239        static void setBackgroundColor(View view, Palette.Swatch swatch) {
240            if (view != null && swatch != null) {
241                view.setBackgroundColor(swatch.getRgb());
242            }
243        }
244
245    }
246
247}