/*
* 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.google.android.glass.sample.apidemo.card;
import com.google.android.glass.media.Sounds;
import com.google.android.glass.sample.apidemo.R;
import com.google.android.glass.widget.CardBuilder;
import com.google.android.glass.widget.CardScrollView;
import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Creates a card scroll view with various examples of its API.
*/
public final class CardScrollViewActivity extends Activity {
/** Actions associated with cards. */
private enum Action {
DELETION_HERE(R.string.text_card_tap_to_delete, R.drawable.codemonkey1),
NAVIGATION_TO_BEGIN(R.string.text_card_tap_to_navigate_begin, R.drawable.codemonkey2),
NAVIGATION_TO_END(R.string.text_card_tap_to_navigate_end, R.drawable.codemonkey3),
INSERTION_AT_BEGIN(R.string.text_card_tap_to_insert_begin, R.drawable.codemonkey4),
INSERTION_BEFORE(R.string.text_card_tap_to_insert_before, R.drawable.codemonkey5),
INSERTION_AFTER(R.string.text_card_tap_to_insert_after, R.drawable.codemonkey6),
INSERTION_AT_END(R.string.text_card_tap_to_insert_end, R.drawable.codemonkey7),
NO_ACTION(R.string.text_card_no_action, R.drawable.codemonkey8);
final int textId;
final int imageId;
Action(int textId, int imageId) {
this.textId = textId;
this.imageId = imageId;
}
}
/**
* Adapter class that handles list of cards with associated actions and
* allows for mutations without notifying the adapter of the data change yet
* (through method {@link #notifyDataSetChanged}). Useful to demonstrate
* mutation animations.
*/
private final class CardAdapterWithMutations extends CardAdapter {
private final List<Action> mActions;
public CardAdapterWithMutations() {
super(new ArrayList<CardBuilder>());
mActions = new ArrayList<Action>();
}
/** Inserts a card into the adapter, without notifying. */
public void insertCardWithoutNotification(int position, CardBuilder card, Action action) {
mCards.add(position, card);
mActions.add(position, action);
}
/** Deletes card from the adapter, without notifying. */
public void deleteCardWithoutNotification(int position) {
mCards.remove(position);
mActions.remove(position);
}
/** Returns the action associated with the card at position. */
public Action getActionAt(int position) {
return mActions.get(position);
}
}
private final Random mRandom = new Random();
private CardScrollView mCardScroller;
private CardAdapterWithMutations mAdapter;
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
mCardScroller = new CardScrollView(this);
setupAdapter();
setupClickListener();
setContentView(mCardScroller);
}
/**
* Sets up adapter.
*/
private void setupAdapter() {
mAdapter = new CardAdapterWithMutations();
// Insert initial cards, one of each kind.
for (int i = 0; i < 8; i++) {
int position = i;
Action action = Action.values()[i];
CardBuilder card = new CardBuilder(this, CardBuilder.Layout.COLUMNS);
card.setText(action.textId).addImage(action.imageId);
mAdapter.insertCardWithoutNotification(position, card, action);
}
// Setting adapter notifies the card scroller of new content.
mCardScroller.setAdapter(mAdapter);
}
/**
* Sets up click listener.
*/
private void setupClickListener() {
mCardScroller.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
switch (mAdapter.getActionAt(position)) {
case DELETION_HERE:
am.playSoundEffect(Sounds.TAP);
deleteCard(position);
break;
case NAVIGATION_TO_BEGIN:
am.playSoundEffect(Sounds.TAP);
navigateToCard(0);
break;
case NAVIGATION_TO_END:
am.playSoundEffect(Sounds.TAP);
navigateToCard(mAdapter.getCount() - 1);
break;
case INSERTION_AT_BEGIN:
am.playSoundEffect(Sounds.TAP);
insertNewCard(0);
break;
case INSERTION_BEFORE:
am.playSoundEffect(Sounds.TAP);
insertNewCard(position);
break;
case INSERTION_AFTER:
am.playSoundEffect(Sounds.TAP);
insertNewCard(position + 1);
break;
case INSERTION_AT_END:
am.playSoundEffect(Sounds.TAP);
insertNewCard(mAdapter.getCount());
break;
default:
am.playSoundEffect(Sounds.DISALLOWED);
break;
}
}
});
}
/**
* Deletes a card at the given position using proper insertion animation
* (the card scroller will animate the old card from view).
*/
private void deleteCard(int position) {
// Delete card in the adapter, but don't call notifyDataSetChanged() yet.
// Instead, request proper animation for deleted card from card scroller,
// which will notify the adapter at the right time during the animation.
mAdapter.deleteCardWithoutNotification(position);
mCardScroller.animate(position, CardScrollView.Animation.DELETION);
}
/** Navigates to card at given position. */
private void navigateToCard(int position) {
mCardScroller.animate(position, CardScrollView.Animation.NAVIGATION);
}
/**
* Inserts a new card at the given position using proper insertion animation
* (the card scroller will animate to the new card).
*/
private void insertNewCard(int position) {
// Insert new card in the adapter, but don't call notifyDataSetChanged()
// yet. Instead, request proper animation to inserted card from card scroller,
// which will notify the adapter at the right time during the animation.
CardBuilder card = new CardBuilder(this, CardBuilder.Layout.COLUMNS);
Action action = Action.values()[mRandom.nextInt(8)];
card.setText(action.textId).addImage(action.imageId);
mAdapter.insertCardWithoutNotification(position, card, action);
mCardScroller.animate(position, CardScrollView.Animation.INSERTION);
}
@Override
protected void onResume() {
super.onResume();
mCardScroller.activate();
}
@Override
protected void onPause() {
mCardScroller.deactivate();
super.onPause();
}
}