/*
* 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.torrenttunes.android.ui;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.FragmentManager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.MediaRouteButton;
import android.support.v7.media.MediaRouter;
import android.support.v7.widget.Toolbar;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import com.torrenttunes.android.R;
import com.torrenttunes.android.utils.LogHelper;
import com.torrenttunes.android.utils.PrefUtils;
import com.torrenttunes.android.utils.ResourceHelper;
import com.github.amlcurran.showcaseview.ShowcaseView;
import com.github.amlcurran.showcaseview.targets.ViewTarget;
import com.google.android.libraries.cast.companionlibrary.cast.VideoCastManager;
import com.google.android.libraries.cast.companionlibrary.cast.callbacks.VideoCastConsumerImpl;
/**
* Abstract activity with toolbar, navigation drawer and cast support. Needs to be extended by
* any activity that wants to be shown as a top level activity.
*
* The requirements for a subclass is to call {@link #initializeToolbar()} on onCreate, after
* setContentView() is called and have three mandatory layout elements:
* a {@link android.support.v7.widget.Toolbar} with id 'toolbar',
* a {@link android.support.v4.widget.DrawerLayout} with id 'drawerLayout' and
* a {@link android.widget.ListView} with id 'drawerList'.
*/
public abstract class ActionBarCastActivity extends ActionBarActivity {
private static final String TAG = LogHelper.makeLogTag(ActionBarCastActivity.class);
private static final int DELAY_MILLIS = 1000;
private VideoCastManager mCastManager;
private MenuItem mMediaRouteMenuItem;
private Toolbar mToolbar;
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private DrawerMenuContents mDrawerMenuContents;
private boolean mToolbarInitialized;
private int mItemToOpenWhenDrawerCloses = -1;
private VideoCastConsumerImpl mCastConsumer = new VideoCastConsumerImpl() {
@Override
public void onFailed(int resourceId, int statusCode) {
LogHelper.d(TAG, "onFailed ", resourceId, " status ", statusCode);
}
@Override
public void onConnectionSuspended(int cause) {
LogHelper.d(TAG, "onConnectionSuspended() was called with cause: ", cause);
}
@Override
public void onConnectivityRecovered() {
}
@Override
public void onCastDeviceDetected(final MediaRouter.RouteInfo info) {
// FTU stands for First Time Use:
if (!PrefUtils.isFtuShown(ActionBarCastActivity.this)) {
// If user is seeing the cast button for the first time, we will
// show an overlay that explains what that button means.
PrefUtils.setFtuShown(ActionBarCastActivity.this, true);
LogHelper.d(TAG, "Route is visible: ", info);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (mMediaRouteMenuItem.isVisible()) {
LogHelper.d(TAG, "Cast Icon is visible: ", info.getName());
showFtu();
}
}
}, DELAY_MILLIS);
}
}
};
private DrawerLayout.DrawerListener mDrawerListener = new DrawerLayout.DrawerListener() {
@Override
public void onDrawerClosed(View drawerView) {
if (mDrawerToggle != null) mDrawerToggle.onDrawerClosed(drawerView);
int position = mItemToOpenWhenDrawerCloses;
if (position >= 0) {
//Bundle extras = ActivityOptions.makeCustomAnimation(
// ActionBarCastActivity.this, R.anim.fade_in, R.anim.fade_out).toBundle();
Class activityClass = mDrawerMenuContents.getActivity(position);
startActivity(new Intent(ActionBarCastActivity.this, activityClass));
}
}
@Override
public void onDrawerStateChanged(int newState) {
if (mDrawerToggle != null) mDrawerToggle.onDrawerStateChanged(newState);
}
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
if (mDrawerToggle != null) mDrawerToggle.onDrawerSlide(drawerView, slideOffset);
}
@Override
public void onDrawerOpened(View drawerView) {
if (mDrawerToggle != null) mDrawerToggle.onDrawerOpened(drawerView);
getSupportActionBar().setTitle(R.string.app_name);
}
};
private FragmentManager.OnBackStackChangedListener mBackStackChangedListener =
new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
updateDrawerToggle();
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LogHelper.d(TAG, "Activity onCreate");
// Ensure that Google Play Service is available.
VideoCastManager.checkGooglePlayServices(this);
mCastManager = VideoCastManager.getInstance();
mCastManager.reconnectSessionIfPossible();
}
@Override
protected void onStart() {
super.onStart();
if (!mToolbarInitialized) {
throw new IllegalStateException("You must run super.initializeToolbar at " +
"the end of your onCreate method");
}
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
if (mDrawerToggle != null) {
mDrawerToggle.syncState();
}
}
@Override
public void onResume() {
super.onResume();
mCastManager.addVideoCastConsumer(mCastConsumer);
mCastManager.incrementUiCounter();
// Whenever the fragment back stack changes, we may need to update the
// action bar toggle: only top level screens show the hamburger-like icon, inner
// screens - either Activities or fragments - show the "Up" icon instead.
getSupportFragmentManager().addOnBackStackChangedListener(mBackStackChangedListener);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (mDrawerToggle != null) {
mDrawerToggle.onConfigurationChanged(newConfig);
}
}
@Override
public void onPause() {
super.onPause();
mCastManager.removeVideoCastConsumer(mCastConsumer);
mCastManager.decrementUiCounter();
getSupportFragmentManager().removeOnBackStackChangedListener(mBackStackChangedListener);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.main, menu);
mMediaRouteMenuItem = mCastManager.addMediaRouterButton(menu, R.id.media_route_menu_item);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle != null && mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// If not handled by drawerToggle, home needs to be handled by returning to previous
if (item != null && item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
// If the drawer is open, back will close it
if (mDrawerLayout != null && mDrawerLayout.isDrawerOpen(Gravity.START)) {
mDrawerLayout.closeDrawers();
return;
}
// Otherwise, it may return to the previous fragment stack
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
} else {
// Lastly, it will rely on the system behavior for back
super.onBackPressed();
}
}
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mToolbar.setTitle(title);
}
@Override
public void setTitle(int titleId) {
super.setTitle(titleId);
mToolbar.setTitle(titleId);
}
protected void initializeToolbar() {
mToolbar = (Toolbar) findViewById(R.id.toolbar);
if (mToolbar == null) {
throw new IllegalStateException("Layout is required to include a Toolbar with id " +
"'toolbar'");
}
mToolbar.inflateMenu(R.menu.main);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
if (mDrawerLayout != null) {
mDrawerList = (ListView) findViewById(R.id.drawer_list);
if (mDrawerList == null) {
throw new IllegalStateException("A layout with a drawerLayout is required to" +
"include a ListView with id 'drawerList'");
}
// Create an ActionBarDrawerToggle that will handle opening/closing of the drawer:
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
mToolbar, R.string.open_content_drawer, R.string.close_content_drawer);
mDrawerLayout.setDrawerListener(mDrawerListener);
mDrawerLayout.setStatusBarBackgroundColor(
ResourceHelper.getThemeColor(this, R.attr.colorPrimary, android.R.color.black));
populateDrawerItems();
setSupportActionBar(mToolbar);
updateDrawerToggle();
} else {
setSupportActionBar(mToolbar);
}
mToolbarInitialized = true;
}
private void populateDrawerItems() {
mDrawerMenuContents = new DrawerMenuContents(this);
final int selectedPosition = mDrawerMenuContents.getPosition(this.getClass());
final int unselectedColor = Color.WHITE;
final int selectedColor = getResources().getColor(R.color.drawer_item_selected_background);
SimpleAdapter adapter = new SimpleAdapter(this, mDrawerMenuContents.getItems(),
R.layout.drawer_list_item,
new String[]{DrawerMenuContents.FIELD_TITLE, DrawerMenuContents.FIELD_ICON},
new int[]{R.id.drawer_item_title, R.id.drawer_item_icon}) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
int color = unselectedColor;
if (position == selectedPosition) {
color = selectedColor;
}
view.setBackgroundColor(color);
return view;
}
};
mDrawerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position != selectedPosition) {
view.setBackgroundColor(getResources().getColor(
R.color.drawer_item_selected_background));
mItemToOpenWhenDrawerCloses = position;
}
mDrawerLayout.closeDrawers();
}
});
mDrawerList.setAdapter(adapter);
}
protected void updateDrawerToggle() {
if (mDrawerToggle == null) {
return;
}
boolean isRoot = getSupportFragmentManager().getBackStackEntryCount() == 0;
mDrawerToggle.setDrawerIndicatorEnabled(isRoot);
getSupportActionBar().setDisplayShowHomeEnabled(!isRoot);
getSupportActionBar().setDisplayHomeAsUpEnabled(!isRoot);
getSupportActionBar().setHomeButtonEnabled(!isRoot);
if (isRoot) {
mDrawerToggle.syncState();
}
}
/**
* Shows the Cast First Time User experience to the user (an overlay that explains what is
* the Cast icon)
*/
private void showFtu() {
Menu menu = mToolbar.getMenu();
View view = menu.findItem(R.id.media_route_menu_item).getActionView();
if (view != null && view instanceof MediaRouteButton) {
new ShowcaseView.Builder(this)
.setTarget(new ViewTarget(view))
.setContentTitle(R.string.touch_to_cast)
.hideOnTouchOutside()
.build();
}
}
}