Android Open Source - LollipopDemo Wearable Sync Activity






From Project

Back to project page LollipopDemo.

License

The source code is released under:

Apache License

If you think the Android project LollipopDemo listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.ToxicBakery.lollipop.demo;
//from  w w w  .  j  a va2s .c  o m
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.LoaderManager;
import android.content.Context;
import android.content.CursorLoader;
import android.content.IntentSender;
import android.content.Loader;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.support.v13.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.LruCache;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;

import com.ToxicBakery.lollipop.R;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.wearable.Asset;
import com.google.android.gms.wearable.DataApi;
import com.google.android.gms.wearable.DataEventBuffer;
import com.google.android.gms.wearable.MessageApi;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.PutDataMapRequest;
import com.google.android.gms.wearable.PutDataRequest;
import com.google.android.gms.wearable.Wearable;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;

public class WearableSyncActivity extends Activity implements LoaderManager.LoaderCallbacks<Cursor>,
        DataApi.DataListener, GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener, ViewPager.OnPageChangeListener {

    private static final LruCache<String, Bitmap> BITMAP_LRU_CACHE;
    private static final int WEAR_SCREEN_SIZE_PX = 320;

    // Wear information
    private static final int REQUEST_RESOLVE_ERROR = 1000;
    private static final String START_ACTIVITY_PATH = "/start-wearableSyncActivity";
    private static final String IMAGE_PATH = "/image";
    private static final String IMAGE_KEY = "photo";

    static {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        final int cacheSize = maxMemory / 8;

        BITMAP_LRU_CACHE = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getAllocationByteCount() / 1024;
            }
        };
    }

    private static final String[] GALLERY_PROJECTION = new String[]{
            MediaStore.Images.Media._ID,
            MediaStore.Images.Media.DATE_TAKEN
    };

    private ViewPager viewPager;
    private GalleryAdapter galleryAdapter;
    private GoogleApiClient googleApiClient;
    private boolean isResolvingError = false;
    private int pageSelected;

    /**
     * Builds an {@link com.google.android.gms.wearable.Asset} from a bitmap. The image that we get
     * back from the camera in "data" is a thumbnail size. Typically, your image should not exceed
     * 320x320 and if you want to have zoom and parallax effect in your app, limit the size of your
     * image to 640x400. Resize your image before transferring to your wearable device.
     */
    private static Asset toAsset(Bitmap bitmap) {
        ByteArrayOutputStream byteStream = null;
        try {
            byteStream = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream);
            return Asset.createFromBytes(byteStream.toByteArray());
        } finally {
            if (byteStream != null) {
                try {
                    byteStream.close();
                } catch (IOException e) {
                    // ignore
                }
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_wearable_sync);

        galleryAdapter = new GalleryAdapter(getFragmentManager());

        viewPager = (ViewPager) findViewById(R.id.demo_wearable_sync_viewpager);
        viewPager.setAdapter(galleryAdapter);
        viewPager.setOnPageChangeListener(this);

        getLoaderManager().initLoader(0, null, this);

        googleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Wearable.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
    }

    @Override
    protected void onResume() {
        super.onResume();

        new StartWearableActivityTask().execute();
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (!isResolvingError) {
            googleApiClient.connect();
        }
    }

    @Override
    protected void onStop() {
        if (!isResolvingError) {
            Wearable.DataApi.removeListener(googleApiClient, this);
            googleApiClient.disconnect();
        }
        super.onStop();
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new CursorLoader(this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, GALLERY_PROJECTION, null, null,
                null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        galleryAdapter.setCursor(cursor);
        galleryAdapter.notifyDataSetChanged();
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        galleryAdapter.setCursor(null);
        galleryAdapter.notifyDataSetChanged();
    }

    @Override
    public void onPageScrolled(int i, float v, int i2) {
    }

    @Override
    public void onPageSelected(int i) {
        pageSelected = i;
        System.out.println("onpage selected: " + i);
        ((FragmentGalleryImage) galleryAdapter.instantiateItem(viewPager, i)).sendPhoto();
    }

    @Override
    public void onPageScrollStateChanged(int i) {
    }

    @Override
    public void onConnected(Bundle bundle) {
        isResolvingError = false;
        Wearable.DataApi.addListener(googleApiClient, this);
    }

    @Override
    public void onConnectionSuspended(int i) {
    }

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        dataEvents.close();
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        if (!isResolvingError) {
            if (connectionResult.hasResolution()) {
                try {
                    isResolvingError = true;
                    connectionResult.startResolutionForResult(this, REQUEST_RESOLVE_ERROR);
                } catch (IntentSender.SendIntentException e) {
                    googleApiClient.connect();
                }
            } else {
                isResolvingError = false;
                Wearable.DataApi.removeListener(googleApiClient, this);
            }
        }
    }

    private Collection<String> getNodes() {
        Collection<String> results = new HashSet<String>();
        NodeApi.GetConnectedNodesResult nodes =
                Wearable.NodeApi.getConnectedNodes(googleApiClient).await();

        for (Node node : nodes.getNodes()) {
            results.add(node.getId());
        }

        return results;
    }

    private void sendStartActivityMessage(String node) {
        Wearable.MessageApi.sendMessage(
                googleApiClient, node, START_ACTIVITY_PATH, new byte[0]).setResultCallback(
                new ResultCallback<MessageApi.SendMessageResult>() {
                    @Override
                    public void onResult(MessageApi.SendMessageResult sendMessageResult) {
                    }
                }
        );
    }

    /**
     * Sends the asset that was created form the photo we took by adding it to the Data Item store.
     */
    private void sendPhoto(Asset asset) {
        PutDataMapRequest dataMap = PutDataMapRequest.create(IMAGE_PATH);
        dataMap.getDataMap().putAsset(IMAGE_KEY, asset);
        dataMap.getDataMap().putLong("time", new Date().getTime());
        PutDataRequest request = dataMap.asPutDataRequest();
        Wearable.DataApi.putDataItem(googleApiClient, request)
                .setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
                    @Override
                    public void onResult(DataApi.DataItemResult dataItemResult) {
                    }
                });

    }

    public static final class FragmentGalleryImage extends Fragment {

        private static final String EXTRA_GALLERY_IMAGE = FragmentGalleryImage.class.getSimpleName() +
                ".EXTRA_GALLERY_IMAGE";

        private static int lastSent;

        private GalleryImage galleryImage;
        private ImageView imageViewImage;
        private TextView textViewDateTaken;
        private ImageLoader imageLoader;

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            galleryImage = getArguments().getParcelable(EXTRA_GALLERY_IMAGE);
        }

        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_gallery_image, container, false);

            imageViewImage = (ImageView) view.findViewById(R.id.fragment_gallery_image_imageview_image);
            textViewDateTaken = (TextView) view.findViewById(R.id.fragment_gallery_image_textview_date_taken);

            imageLoader = new ImageLoader(imageViewImage, new ImageLoader.ICallback() {
                @Override
                public void onFinished() {
                    sendPhoto();
                }
            });

            return view;
        }

        @Override
        public void onResume() {
            super.onResume();

            Date date = new Date(galleryImage.dateTaken);

            imageViewImage.setVisibility(View.INVISIBLE);
            textViewDateTaken.setText(SimpleDateFormat.getInstance().format(date));

            imageLoader.execute(galleryImage);
        }

        @Override
        public void onPause() {
            super.onPause();

            imageLoader.cancel(false);
        }

        private void sendPhoto() {
            WearableSyncActivity activity = (WearableSyncActivity) getActivity();
            if (activity != null && activity.galleryAdapter.instantiateItem(activity.viewPager,
                    activity.pageSelected) == this) {
                Bitmap bitmap = BITMAP_LRU_CACHE.get(ImageLoader.getWearImageCacheName(galleryImage));
                if (bitmap != null) {
                    lastSent = activity.pageSelected;
                    activity.sendPhoto(toAsset(bitmap));
                }
            }
        }

        private static final class ImageLoader extends AsyncTask<GalleryImage, Void, Bitmap> {

            private final ImageView imageView;
            private final Context context;

            private Bitmap wearBitmap;
            private ICallback callback;

            private ImageLoader(ImageView imageView, ICallback callback) {
                this.imageView = imageView;
                this.callback = callback;
                context = imageView.getContext().getApplicationContext();
            }

            public static String getWearImageCacheName(GalleryImage galleryImage) {
                return getImageUri(galleryImage).toString().replaceAll("[^a-zA-Z0-9.]", "") + "small";
            }

            public static Uri getImageUri(GalleryImage galleryImage) {
                return Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                        Integer.toString(galleryImage._id));
            }

            private static void calculateInSampleSize(
                    BitmapFactory.Options options, int reqWidth, int reqHeight) {
                // Raw height and width of image
                final int height = options.outHeight;
                final int width = options.outWidth;
                options.inSampleSize = 1;

                if (height > reqHeight || width > reqWidth) {

                    final int halfHeight = height / 2;
                    final int halfWidth = width / 2;

                    // Calculate the largest inSampleSize value that is a power of 2 and keeps both
                    // height and width larger than the requested height and width.
                    while ((halfHeight / options.inSampleSize) > reqHeight
                            && (halfWidth / options.inSampleSize) > reqWidth) {
                        options.inSampleSize *= 2;
                    }

                    options.outHeight = height / options.inSampleSize;
                    options.outWidth = width / options.inSampleSize;
                }
            }

            @Override
            protected Bitmap doInBackground(GalleryImage... galleryImages) {
                Uri uri = getImageUri(galleryImages[0]);
                String uriString = uri.toString();

                Bitmap bitmap = BITMAP_LRU_CACHE.get(uriString);

                if (bitmap != null)
                    return bitmap;

                try {
                    bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
                } catch (IOException e) {
                    e.printStackTrace();
                }

                BITMAP_LRU_CACHE.put(uriString, bitmap);

                // Downscale for wearBitmap
                String wearCacheName = getWearImageCacheName(galleryImages[0]);
                File wearFile = new File(context.getCacheDir(), wearCacheName);

                if (wearFile.exists()) {
                    wearBitmap = BitmapFactory.decodeFile(wearFile.getAbsolutePath());
                    BITMAP_LRU_CACHE.put(wearCacheName, wearBitmap);
                } else {
                    try {
                        FileDescriptor imageDescriptor = context.getContentResolver().openFileDescriptor
                                (uri, "r").getFileDescriptor();

                        BitmapFactory.Options options = new BitmapFactory.Options();
                        options.inJustDecodeBounds = true;
                        BitmapFactory.decodeFileDescriptor(imageDescriptor, null, options);
                        calculateInSampleSize(options, WEAR_SCREEN_SIZE_PX, WEAR_SCREEN_SIZE_PX);
                        options.inJustDecodeBounds = false;

                        wearBitmap = BitmapFactory.decodeFileDescriptor(imageDescriptor, null, options);

                        BITMAP_LRU_CACHE.put(wearCacheName, wearBitmap);

                        // cache to disk
                        OutputStream os = new FileOutputStream(wearFile);
                        wearBitmap.compress(Bitmap.CompressFormat.JPEG, 70, os);
                        os.flush();
                        os.close();

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                return bitmap;
            }

            @Override
            protected void onPostExecute(Bitmap bitmap) {
                imageView.setVisibility(View.VISIBLE);

                if (bitmap == null) {
                    imageView.setScaleType(ImageView.ScaleType.CENTER);
                    imageView.setImageResource(R.drawable.ic_launcher);
                } else {
                    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                    imageView.setImageBitmap(bitmap);
                }

                callback.onFinished();
                callback = null;
            }

            @Override
            protected void onCancelled() {
                super.onCancelled();

                callback = null;
            }

            private static interface ICallback {

                void onFinished();
            }

        }

    }

    private static final class GalleryImage implements Parcelable {

        public static final Creator CREATOR = new Creator() {
            @Override
            public Object createFromParcel(Parcel source) {
                return new GalleryImage(source);
            }

            @Override
            public GalleryImage[] newArray(int size) {
                return new GalleryImage[0];
            }
        };

        private final int _id;
        private final long dateTaken;

        private GalleryImage(Cursor cursor) {
            int indexId = cursor.getColumnIndex(MediaStore.Images.Media._ID);
            int indexDateTaken = cursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN);

            _id = cursor.getInt(indexId);
            dateTaken = Long.parseLong(cursor.getString(indexDateTaken));
        }

        private GalleryImage(Parcel parcel) {
            _id = parcel.readInt();
            dateTaken = parcel.readLong();
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(_id);
            dest.writeLong(dateTaken);
        }
    }

    private static final class GalleryAdapter extends FragmentStatePagerAdapter {

        private Cursor cursor;

        private GalleryAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int i) {
            cursor.moveToPosition(i);

            Bundle bundle = new Bundle();
            bundle.putParcelable(FragmentGalleryImage.EXTRA_GALLERY_IMAGE, new GalleryImage(cursor));

            FragmentGalleryImage fragmentGalleryImage = new FragmentGalleryImage();
            fragmentGalleryImage.setArguments(bundle);

            return fragmentGalleryImage;
        }

        @Override
        public int getCount() {
            return cursor == null ? 0 : cursor.getCount();
        }

        public void setCursor(Cursor cursor) {
            this.cursor = cursor;
        }
    }

    private class StartWearableActivityTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... args) {
            Collection<String> nodes = getNodes();
            for (String node : nodes) {
                sendStartActivityMessage(node);
            }
            return null;
        }
    }
}




Java Source Code List

com.ToxicBakery.lollipop.DataLayerListenerService.java
com.ToxicBakery.lollipop.DemoWearActivity.java
com.ToxicBakery.lollipop.MainActivity.java
com.ToxicBakery.lollipop.demo.CardViewActivity.java
com.ToxicBakery.lollipop.demo.NewActivityTransitionsActivity.java
com.ToxicBakery.lollipop.demo.RecyclerViewActivity.java
com.ToxicBakery.lollipop.demo.RevealActivity.java
com.ToxicBakery.lollipop.demo.RippleActivity.java
com.ToxicBakery.lollipop.demo.WearableNotificationsActivity.java
com.ToxicBakery.lollipop.demo.WearableSyncActivity.java
lollipop.toxicbakery.com.lollipopdemo.ApplicationTest.java