Upgrade to Pro — share decks privately, control downloads, hide ads and more …

WearSquare: Introduction to Android Wear Design & Development

WearSquare: Introduction to Android Wear Design & Development

David Vávra

January 06, 2015
Tweet

More Decks by David Vávra

Other Decks in Technology

Transcript

  1. WearSquare
    Introduction to
    Android Wear Design & Development
    David Vávra

    View Slide

  2. View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. Design principles
    and how to implement them in native code

    View Slide

  7. Focus on not stopping the user and all
    else will follow
    1/5
    Wearable UI Library
    DelayedConfirmationView

    View Slide

  8. DelayedConfirmationView
    android:id="@+id/confirmation"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:src="@drawable/ic_cancel"
    app:circle_color="@color/action_button"
    app:circle_radius="40dp"
    app:circle_radius_pressed="35dp"
    app:circle_padding="5dp"
    app:circle_border_width="5dp"
    app:circle_border_color="@color/primary_light"/>
    /wear/src/main/res/layout/fragment_check_in.xml
    vConfirmation.setTotalTimeMs(3000);
    vConfirmation.start();
    mTimerInvalid = false;
    vConfirmation.setListener(new DelayedConfirmationView.
    DelayedConfirmationListener() {
    @Override
    public void onTimerFinished(View view) {
    if (!mTimerInvalid) {
    ((CheckInActivity)getActivity()).sendCheckInMessage();
    }
    }
    @Override
    public void onTimerSelected(View view) {
    mTimerInvalid = true;
    getActivity().finish();
    }
    });
    /wear/src/main/java/cz/destil/wearsquare/fragment/CheckInFragment.java

    View Slide

  9. Design for big gestures
    2/5
    3 items on screen
    WearableListView

    View Slide

  10. WearableListView
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
    /wear/src/main/res/layout/activity_fragment_list.xml
    public class CheckInListAdapter extends WearableListView.Adapter {
    public CheckInListAdapter(Context context, List items){}
    @Override
    public WearableListView.ViewHolder onCreateViewHolder(ViewGroup
    viewGroup, int i) {}
    @Override
    public void onBindViewHolder(WearableListView.ViewHolder
    viewHolder, int position) {}
    @Override
    public int getItemCount() {}
    class ListItem extends FrameLayout implements WearableListView.
    OnCenterProximityListener {
    @Override
    public void onCenterPosition(boolean b) {}
    @Override
    public void onNonCenterPosition(boolean b) {}
    }
    } /wear/src/main/java/cz/destil/wearsquare/adapter/CheckInListAdapter.java

    View Slide

  11. Think about stream cards first
    3/5
    It would be best to show
    card automatically
    But Don’t be a constant
    shoulder tapper
    GridViewPager
    FragmentGridPagerAdapter
    CardFragment

    View Slide

  12. FragmentGridPagerAdapter
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/black"
    android:keepScreenOn="true"/>
    android:id="@+id/page_indicator"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal|bottom"/>

    /wear/src/main/res/layout/activity_gridpager.xml
    public class ExploreAdapter extends FragmentGridPagerAdapter
    {
    public ExploreAdapter(ExploreActivity activity,
    List items) {}
    @Override
    public Fragment getFragment(int row, int col) {
    final Venue venue = mItems.get(row);
    CardFragment fragment = CardFragment.create(venue.
    name, venue.tip);
    }
    @Override
    public Drawable getBackgroundForRow(int row) {}
    @Override
    public int getRowCount() {return mItems.size();}
    @Override
    public int getColumnCount(int rowNum) {}
    }
    /wear/src/main/java/cz/destil/wearsquare/adapter/ExploreAdapter.java

    View Slide

  13. Do one thing, really fast
    4/5
    Display most
    important data +
    action buttons
    CircledImageView
    ActionFragment

    View Slide

  14. ActionFragment

    android:layout_width="match_parent"
    android:layout_height="match_parent">
    android:id="@+id/icon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    app:circle_color="@color/action_button"
    app:circle_radius="45dp"
    app:circle_border_width="0dp"/>
    .../>

    /wear/src/main/res/layout/fragment_action.xml
    public class ActionFragment extends BaseFragment implements
    View.OnClickListener {
    public static ActionFragment create(int iconResId, int
    labelResId, Listener listener) {}
    @Override
    public void onViewCreated(View view, Bundle
    savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    vIcon.setImageResource(getArguments().getInt("ICON"));
    vLabel.setText(getArguments().getInt("LABEL"));
    view.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
    mListener.onActionPerformed();}
    public interface Listener {
    public void onActionPerformed();
    }
    } /wear/src/main/java/cz/destil/wearsquare/fragment/ActionFragment.java

    View Slide

  15. Design for the corner of the eye
    5/5
    ConfirmationActivity:
    ○ success
    ○ failure
    ○ open on phone

    View Slide

  16. ConfirmationActivity
    Intent i = new Intent(this, ConfirmationActivity.class);
    i.putExtra(ConfirmationActivity.EXTRA_ANIMATION_TYPE, ConfirmationActivity.SUCCESS_ANIMATION);
    i.putExtra(ConfirmationActivity.EXTRA_MESSAGE, getString(R.string.checked_in));
    startActivityForResult(i, CheckInActivity.CONFIRM_ACTIVITY);
    /wear/src/main/java/cz/destil/wearsquare/activity/CheckInActivity.java

    View Slide

  17. Q&A
    Code: https://github.com/destil/wearsquare
    App: https://play.google.com/store/apps/details?id=cz.destil.wearsquare

    View Slide

  18. Development tips

    View Slide

  19. Use Teleport library
    1/3
    Removes boilerplate code from Data Layer API
    https://github.com/Mariuxtheone/Teleport by GDE Mario Viviani
    mTeleportClient.syncString("hello", "Hello, World!");
    /mobile/...
    mTeleportClient.setOnSyncDataItemTask(new ShowToastHelloWorldTask());
    public class ShowToastHelloWorldTask extends TeleportClient.OnSyncDataItemTask {
    @Override
    protected void onPostExecute(DataMap dataMap) {
    String hello = dataMap.getString("hello");
    Toast.makeText(context, hello, Toast.LENGTH_SHORT).show();
    }
    } /wear/...

    View Slide

  20. Sync images later
    2/3
    private void downloadImages(Set imageUrls) {
    int i = 0;
    mTargets = new SparseArray<>();
    for (final String imageUrl : imageUrls) {
    mTargets.put(i, new Target() {
    @Override
    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
    Asset asset = ImageUtils.createAssetFromBitmap(bitmap);
    final PutDataMapRequest data = PutDataMapRequest.createWithAutoAppendedId("/image");
    data.getDataMap().putString("image_url", imageUrl);
    data.getDataMap().putAsset("asset", asset);
    syncDataItem(data);
    }
    @Override
    public void onBitmapFailed(Drawable errorDrawable) {}
    });
    Picasso.with(App.get()).load(imageUrl).into(mTargets.get(i));
    i++;
    }
    } /mobile/src/main/java/cz/destil/wearsquare/service/FoursquareService.java

    View Slide

  21. Send unhandled Exceptions to phone
    3/3
    public class App extends Application {
    @Override
    public void onCreate() {
    super.onCreate();
    Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(Thread.getDefaultUncaughtExceptionHandler()));
    }
    } /wear/src/main/java/cz/destil/wearsquare/core/App.java
    public class ExceptionHandler implements Thread.UncaughtExceptionHandler {
    public ExceptionHandler(Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler) { }
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
    App.bus().post(new ExceptionEvent(ex));
    mDefaultUncaughtExceptionHandler.uncaughtException(thread, ex);
    }
    public static void sendExceptionToPhone(Throwable exception, TeleportClient mTeleportClient) {
    mTeleportClient.sendMessage(buildMessageText(exception), null);
    }
    } /wear/src/main/java/cz/destil/wearsquare/util/ExceptionHandler.java

    View Slide