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}