Update Support7Demos to include Palette demos

Change-Id: Iff13ca1a2551e54a98c655955654cf8be5930d0b
This commit is contained in:
Chris Banes
2014-05-19 16:32:48 +01:00
parent a29134d404
commit 170658dd69
11 changed files with 772 additions and 0 deletions

View File

@@ -27,6 +27,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-v7-appcompat \
android-support-v7-gridlayout \
android-support-v7-mediarouter \
android-support-v7-palette \
android-support-v7-recyclerview \
android-support-v7-cardview
LOCAL_RESOURCE_DIR = \

View File

@@ -27,6 +27,9 @@
<!-- Permission for SYSTEM_ALERT_WINDOW is only required for emulating
remote display using system alert window. -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- Permission for READ_EXTERNAL_STORAGE is explicitly required for
reading images from the media store from API v19+. -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="17" />
@@ -210,5 +213,18 @@
</intent-filter>
</activity>
<activity android:name=".graphics.PaletteActivity"
android:label="@string/palette"
android:theme="@style/Theme.AppCompat">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".graphics.PaletteDetailActivity"
android:label="@string/palette"
android:theme="@style/Theme.AppCompat" />
</application>
</manifest>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/palette_list_item" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/palette_all_colors"
style="?android:attr/listSeparatorTextViewStyle"/>
<GridView
android:id="@+id/palette"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:columnWidth="@dimen/color_palette_size"
android:numColumns="auto_fit"/>
</LinearLayout>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 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.
-->
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/color_palette_size" />

View File

@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="110dp"
android:divider="?android:attr/dividerHorizontal"
android:orientation="horizontal"
android:showDividers="middle">
<ImageView
android:id="@+id/image"
android:layout_width="130dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="fitCenter" />
<TextView
android:id="@+id/text_light_vibrant"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceInverse"
android:text="LV" />
<TextView
android:id="@+id/text_vibrant"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="V" />
<TextView
android:id="@+id/text_dark_vibrant"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="DV" />
<TextView
android:id="@+id/text_light_muted"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceInverse"
android:text="LM" />
<TextView
android:id="@+id/text_muted"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="M" />
<TextView
android:id="@+id/text_dark_muted"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="DM" />
</LinearLayout>

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_num_colors"
android:title="Num Colors"
app:showAsAction="always">
<menu>
<group android:checkableBehavior="single">
<item
android:id="@+id/menu_num_colors_8"
android:title="8" />
<item
android:id="@+id/menu_num_colors_12"
android:title="12" />
<item
android:id="@+id/menu_num_colors_16"
android:title="16"
android:checked="true" />
<item
android:id="@+id/menu_num_colors_24"
android:title="24" />
<item
android:id="@+id/menu_num_colors_32"
android:title="32" />
</group>
</menu>
</item>
</menu>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<resources>
<dimen name="color_palette_size">60dp</dimen>
</resources>

View File

@@ -114,4 +114,8 @@
<string name="card_view_radius">Radius</string>
<string name="card_view_width">Width</string>
<string name="card_view_height">Height</string>
<string name="palette">Palette</string>
<string name="palette_all_colors">Full color palette</string>
</resources>

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2014 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.example.android.supportv7.graphics;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.provider.MediaStore;
import android.support.v4.graphics.BitmapCompat;
import android.support.v4.os.AsyncTaskCompat;
import android.support.v4.util.LruCache;
import android.widget.ImageView;
/**
* A very naive lazily implemented image loader. Do not use this in production code.
*/
class ImageLoader {
/**
* A LruCache used to store images which has a maximum size of 10% of the maximum heap size.
*/
private static final BitmapCache CACHE = new BitmapCache(
Math.round(Runtime.getRuntime().maxMemory() / 10));
private ImageLoader() {
}
interface Listener {
void onImageLoaded(Bitmap bitmap);
}
static void loadMediaStoreThumbnail(final ImageView imageView,
final long id,
final Listener listener) {
final Bitmap cachedValue = CACHE.get(id);
if (cachedValue != null) {
// If the image is already in the cache, display the image,
// call the listener now and return
imageView.setImageBitmap(cachedValue);
if (listener != null) {
listener.onImageLoaded(cachedValue);
}
return;
}
AsyncTaskCompat.executeParallel(new AsyncTask<Void, Void, Bitmap>() {
@Override
protected Bitmap doInBackground(Void... params) {
return MediaStore.Images.Thumbnails.getThumbnail(
imageView.getContext().getContentResolver(),
id,
MediaStore.Images.Thumbnails.MINI_KIND,
null);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
imageView.setImageBitmap(bitmap);
if (bitmap != null) {
// Add the image to the memory cache first
CACHE.put(id, bitmap);
if (listener != null) {
listener.onImageLoaded(bitmap);
}
}
}
});
}
/**
* A simple cache implementation for {@link android.graphics.Bitmap} instances which uses
* {@link android.support.v4.util.LruCache}.
*/
private static class BitmapCache extends LruCache<Long, Bitmap> {
BitmapCache(int maxSize) {
super(maxSize);
}
@Override
protected int sizeOf(Long key, Bitmap value) {
return BitmapCompat.getAllocationByteCount(value);
}
}
}

View File

@@ -0,0 +1,243 @@
/*
* Copyright (C) 2014 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.example.android.supportv7.graphics;
import com.example.android.supportv7.R;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.ResourceCursorAdapter;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.graphics.Palette;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.ListView;
/**
* Activity which displays the images from the device's {@link MediaStore}, alongside the generated
* {@link android.support.v7.graphics.Palette} results.
*
* Allows the customization of the number of colors used in the palette generation, to demonstrate
* the difference in results for different types of images.
*/
public class PaletteActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportFragmentManager()
.beginTransaction()
.replace(android.R.id.content, new PaletteMediaStoreListFragment())
.commit();
}
/**
* The {@link android.support.v4.app.ListFragment} which does all of the hard work.
*/
public static class PaletteMediaStoreListFragment extends ListFragment
implements LoaderManager.LoaderCallbacks<Cursor> {
/**
* Projection used for querying the {@link android.provider.MediaStore}.
*/
static final String[] PROJECTION = {
MediaStore.Images.ImageColumns._ID,
MediaStore.Images.ImageColumns.DATE_ADDED
};
private PhotosCursorAdapter mAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Enable fast scroll to make it easier to navigate large number of images
getListView().setFastScrollEnabled(true);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Create an Adapter and use a new Adapter
mAdapter = new PhotosCursorAdapter(getActivity(), null);
mAdapter.setNumColors(16);
setListAdapter(mAdapter);
// Start the loader manager to create our CursorLoader
getLoaderManager().initLoader(0, null, this);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.sample_palette_actions, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_num_colors_8:
mAdapter.setNumColors(8);
item.setChecked(true);
return true;
case R.id.menu_num_colors_12:
mAdapter.setNumColors(12);
item.setChecked(true);
return true;
case R.id.menu_num_colors_16:
mAdapter.setNumColors(16);
item.setChecked(true);
return true;
case R.id.menu_num_colors_24:
mAdapter.setNumColors(24);
item.setChecked(true);
return true;
case R.id.menu_num_colors_32:
mAdapter.setNumColors(32);
item.setChecked(true);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
final Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon()
.appendEncodedPath(String.valueOf(id)).build();
// Start the Detail Activity
Intent intent = new Intent(getActivity(), PaletteDetailActivity.class);
intent.setData(uri);
startActivity(intent);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle bundle) {
return new CursorLoader(
getActivity(),
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
PROJECTION,
null,
null,
MediaStore.Images.ImageColumns.DATE_ADDED + " DESC");
}
@Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
mAdapter.swapCursor(cursor);
}
@Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
mAdapter.swapCursor(null);
}
private static class PhotosCursorAdapter extends ResourceCursorAdapter {
private int mNumColors;
public PhotosCursorAdapter(Context context, Cursor c) {
super(context, R.layout.palette_list_item, c, false);
mContext = context;
}
/**
* Set the number of colors used for {@link Palette} generation.
*/
void setNumColors(int numColors) {
mNumColors = numColors;
notifyDataSetChanged();
}
@Override
public void bindView(final View view, Context context, Cursor cursor) {
// Let's reset the view, clearing the ImageView and resetting the background colors
// of the Palette UI
ImageView imageView = (ImageView) view.findViewById(R.id.image);
imageView.setImageDrawable(null);
view.findViewById(R.id.text_vibrant).setBackgroundDrawable(null);
view.findViewById(R.id.text_muted).setBackgroundDrawable(null);
view.findViewById(R.id.text_light_vibrant).setBackgroundDrawable(null);
view.findViewById(R.id.text_light_muted).setBackgroundDrawable(null);
view.findViewById(R.id.text_dark_vibrant).setBackgroundDrawable(null);
view.findViewById(R.id.text_dark_muted).setBackgroundDrawable(null);
final long id = cursor.getLong(
cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns._ID));
ImageLoader.loadMediaStoreThumbnail(imageView, id, new ImageLoader.Listener() {
@Override
public void onImageLoaded(Bitmap bitmap) {
Palette.generateAsync(bitmap, mNumColors,
new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
setBackgroundColor(
view.findViewById(R.id.text_vibrant),
palette.getVibrantSwatch());
setBackgroundColor(
view.findViewById(R.id.text_muted),
palette.getMutedSwatch());
setBackgroundColor(
view.findViewById(R.id.text_light_vibrant),
palette.getLightVibrantSwatch());
setBackgroundColor(
view.findViewById(R.id.text_light_muted),
palette.getLightMutedSwatch());
setBackgroundColor(
view.findViewById(R.id.text_dark_vibrant),
palette.getDarkVibrantSwatch());
setBackgroundColor(
view.findViewById(R.id.text_dark_muted),
palette.getDarkMutedSwatch());
}
});
}
});
}
}
static void setBackgroundColor(View view, Palette.Swatch swatch) {
if (view != null && swatch != null) {
view.setBackgroundColor(swatch.getRgb());
}
}
}
}

View File

@@ -0,0 +1,189 @@
/*
* Copyright (C) 2014 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.example.android.supportv7.graphics;
import com.example.android.supportv7.R;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.graphics.Palette;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.Toast;
import java.util.List;
/**
* Activity which displays the more details about a generated {@link Palette} for a specific
* {@link android.provider.MediaStore} image.
*
* Displays the full generated palette of colors in a grid, which allows clicking on an palette item
* to display more information in a {@link Toast}.
*
* Also allows the customization of the number of colors used in the palette generation for
* demonstration purposes.
*/
public class PaletteDetailActivity extends ActionBarActivity {
private ImageView mImageView;
private GridView mGridView;
private SwatchesPalette mSwatchesPalette;
private Uri mImageUri;
private Toast mCurrentToast;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.palette_activity_detail);
mImageUri = getIntent().getData();
mImageView = (ImageView) findViewById(R.id.image);
mGridView = (GridView) findViewById(R.id.palette);
mSwatchesPalette = new SwatchesPalette();
mGridView.setAdapter(mSwatchesPalette);
// Set an OnItemClickListener to display a information Toast when a Palette item is clicked
mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int pos, long l) {
// Cancel the current Toast if there is already one being displayed
if (mCurrentToast != null) {
mCurrentToast.cancel();
}
final Palette.Swatch item = (Palette.Swatch) adapterView.getItemAtPosition(pos);
mCurrentToast = Toast.makeText(PaletteDetailActivity.this,
item.toString(), Toast.LENGTH_LONG);
mCurrentToast.show();
}
});
// Load the image with a default number of colors
loadImage(16);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.sample_palette_actions, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_num_colors_8:
loadImage(8);
item.setChecked(true);
return true;
case R.id.menu_num_colors_12:
loadImage(12);
item.setChecked(true);
return true;
case R.id.menu_num_colors_16:
loadImage(16);
item.setChecked(true);
return true;
case R.id.menu_num_colors_24:
loadImage(24);
item.setChecked(true);
return true;
case R.id.menu_num_colors_32:
loadImage(32);
item.setChecked(true);
return true;
}
return super.onOptionsItemSelected(item);
}
private void loadImage(final int numColors) {
final int id = Integer.parseInt(mImageUri.getLastPathSegment());
ImageLoader.loadMediaStoreThumbnail(mImageView, id, new ImageLoader.Listener() {
@Override
public void onImageLoaded(Bitmap bitmap) {
Palette.generateAsync(bitmap, numColors, new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
populatePalette(palette);
}
});
}
});
}
private class SwatchesPalette extends BaseAdapter {
private List<Palette.Swatch> mSwatches;
@Override
public int getCount() {
return mSwatches != null ? mSwatches.size() : 0;
}
@Override
public Palette.Swatch getItem(int position) {
return mSwatches.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
void setSwatches(List<Palette.Swatch> palette) {
mSwatches = palette;
notifyDataSetChanged();
}
@Override
public View getView(int position, View view, ViewGroup parent) {
if (view == null) {
view = getLayoutInflater().inflate(R.layout.palette_grid_item, parent, false);
}
setBackgroundColor(view, getItem(position));
return view;
}
}
private void populatePalette(Palette palette) {
mSwatchesPalette.setSwatches(palette.getSwatches());
setBackgroundColor(findViewById(R.id.text_vibrant), palette.getVibrantSwatch());
setBackgroundColor(findViewById(R.id.text_muted), palette.getMutedSwatch());
setBackgroundColor(findViewById(R.id.text_light_vibrant), palette.getLightVibrantSwatch());
setBackgroundColor(findViewById(R.id.text_light_muted), palette.getLightMutedSwatch());
setBackgroundColor(findViewById(R.id.text_dark_vibrant), palette.getDarkVibrantSwatch());
setBackgroundColor(findViewById(R.id.text_dark_muted), palette.getDarkMutedSwatch());
}
private void setBackgroundColor(View view, Palette.Swatch swatch) {
if (view != null && swatch != null) {
view.setBackgroundColor(swatch.getRgb());
}
}
}