Java tutorial
/* * Copyright 2014 Nicholas Liu * * 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. * * Portions Copyright 2014 Google Inc. */ package ca.zadrox.dota2esportticker.ui; import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.support.v4.view.ViewCompat; import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.Toolbar; import android.view.Gravity; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.animation.DecelerateInterpolator; import android.widget.AbsListView; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; import ca.zadrox.dota2esportticker.R; import ca.zadrox.dota2esportticker.service.UpdateMatchService; import ca.zadrox.dota2esportticker.ui.widget.MultiSwipeRefreshLayout; import ca.zadrox.dota2esportticker.ui.widget.ScrimInsetsScrollView; import ca.zadrox.dota2esportticker.util.HelpUtils; import ca.zadrox.dota2esportticker.util.LUtils; import ca.zadrox.dota2esportticker.util.PrefUtils; import ca.zadrox.dota2esportticker.util.TimeUtils; import ca.zadrox.dota2esportticker.util.UIUtils; /** * Created by Acco on 10/20/2014. */ public abstract class BaseActivity extends ActionBarActivity implements SharedPreferences.OnSharedPreferenceChangeListener, MultiSwipeRefreshLayout.CanChildScrollUpCallback { protected static final int NAVDRAWER_ITEM_MATCHES = 0; protected static final int NAVDRAWER_ITEM_TEAMS = 1; protected static final int NAVDRAWER_ITEM_TOURNAMENTS = 2; protected static final int NAVDRAWER_ITEM_NEWS = 3; protected static final int NAVDRAWER_ITEM_SETTINGS = 4; protected static final int NAVDRAWER_ITEM_SEPARATOR = -1; protected static final int NAVDRAWER_ITEM_INVALID = -2; private static final String TAG = BaseActivity.class.getSimpleName(); // hide additional UI elements on scroll private static final int HEADER_HIDE_ANIM_DURATION = 300; // probably not necessary, cause we don't have account... yet. private static final int ACCOUNT_BOX_EXPAND_ANIM_DURATION = 200; private static final int[] NAVDRAWER_TITLE_RES_ID = new int[] { R.string.navdrawer_item_matches, R.string.navdrawer_item_teams, R.string.navdrawer_item_tournaments, R.string.navdrawer_item_news, R.string.navdrawer_item_settings }; private static final int[] NAVDRAWER_ICON_RES_ID = new int[] { R.drawable.ic_drawer_event, R.drawable.ic_drawer_group, R.drawable.ic_drawer_tournament, R.drawable.ic_drawer_subject, R.drawable.ic_drawer_settings }; private static final int NAVDRAWER_LAUNCH_DELAY = 150; private static final int MAIN_CONTENT_FADEOUT_DURATION = 150; private static final int MAIN_CONTENT_FADEIN_DURATION = 250; private static final TypeEvaluator ARGB_EVALUATOR = new ArgbEvaluator(); private DrawerLayout mDrawerLayout; private Handler mHandler; private ViewGroup mDrawerItemsListContainer; private boolean tabChanged; private LUtils mLUtils; private ObjectAnimator mStatusBarColorAnimator; // contains the views that we want to hide when the list is scrolled. private ArrayList<View> mHideableHeaderViews = new ArrayList<View>(); // list of navdrawer items added. private ArrayList<Integer> mNavDrawerItems = new ArrayList<Integer>(); // views associated with each navdrawer item private View[] mNavDrawerItemViews = null; // Used in at least News and Matches. private SwipeRefreshLayout mSwipeRefreshLayout; // ActionBar/Toolbar ref private Toolbar mActionBarToolbar; // Controls for hiding/showing actionbar on scroll. private boolean mActionBarAutoHideEnabled = false; private int mActionBarAutoHideSensitivity = 0; private int mActionBarAutoHideMinY = 0; private int mActionBarAutoHideSignal = 0; private boolean mActionBarShown = true; private Runnable mDeferredOnDrawerClosedRunnable; private int mThemedStatusBarColor; private int mNormalStatusBarColor; private int mProgressBarTopWhenActionBarShown; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mHandler = new Handler(); mLUtils = LUtils.getInstance(this); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); sp.registerOnSharedPreferenceChangeListener(this); ActionBar ab = getSupportActionBar(); if (ab != null) { ab.setDisplayHomeAsUpEnabled(true); } mThemedStatusBarColor = getResources().getColor(R.color.theme_primary_dark); mNormalStatusBarColor = mThemedStatusBarColor; } protected void trySetupSwipeRefresh() { mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout); if (mSwipeRefreshLayout == null) { return; } mSwipeRefreshLayout.setColorSchemeColors(R.color.refresh_progress_1, R.color.refresh_progress_2, R.color.refresh_progress_3, R.color.refresh_progress_4); if (mActionBarShown) { // mSwipeRefreshLayout.setTop(mProgressBarTopWhenActionBarShown); mSwipeRefreshLayout.setProgressViewOffset(true, mProgressBarTopWhenActionBarShown, mProgressBarTopWhenActionBarShown + 100); } else { mSwipeRefreshLayout.setProgressViewOffset(true, 0, UIUtils.calculateActionBarSize(this)); } } protected void setProgressBarTopWhenActionBarShown(int progressBarTopWhenActionBarShown) { mProgressBarTopWhenActionBarShown = progressBarTopWhenActionBarShown; updateSwipeRefreshProgressBarTop(); } private void updateSwipeRefreshProgressBarTop() { if (mSwipeRefreshLayout == null) { return; } if (mActionBarShown) { // mSwipeRefreshLayout.setTop(mProgressBarTopWhenActionBarShown); mSwipeRefreshLayout.setProgressViewOffset(true, mProgressBarTopWhenActionBarShown, mProgressBarTopWhenActionBarShown + 100); } else { // mSwipeRefreshLayout.setTop(0); mSwipeRefreshLayout.setProgressViewOffset(true, 0, UIUtils.calculateActionBarSize(this)); } } protected int getSelfNavDrawerItem() { return NAVDRAWER_ITEM_INVALID; } private void setupNavDrawer() { int selfItem = getSelfNavDrawerItem(); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); if (mDrawerLayout == null) { return; } mDrawerLayout.setStatusBarBackgroundColor(getResources().getColor(R.color.theme_primary_dark)); ScrimInsetsScrollView navDrawer = (ScrimInsetsScrollView) mDrawerLayout.findViewById(R.id.navdrawer); if (selfItem == NAVDRAWER_ITEM_INVALID) { if (navDrawer != null) { ((ViewGroup) navDrawer.getParent()).removeView(navDrawer); } mDrawerLayout = null; return; } if (mActionBarToolbar != null) { mActionBarToolbar.setNavigationIcon(R.drawable.ic_drawer); mActionBarToolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mDrawerLayout.openDrawer(Gravity.START); } }); } mDrawerLayout.setDrawerListener(new DrawerLayout.DrawerListener() { @Override public void onDrawerClosed(View drawerView) { // run deferred action, if we have one if (mDeferredOnDrawerClosedRunnable != null) { mDeferredOnDrawerClosedRunnable.run(); mDeferredOnDrawerClosedRunnable = null; } onNavDrawerStateChanged(false, false); } @Override public void onDrawerOpened(View drawerView) { onNavDrawerStateChanged(true, false); } @Override public void onDrawerStateChanged(int newState) { onNavDrawerStateChanged(isNavDrawerOpen(), newState != DrawerLayout.STATE_IDLE); } @Override public void onDrawerSlide(View drawerView, float slideOffset) { onNavDrawerSlide(slideOffset); } }); mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, Gravity.START); // populate the nav drawer with the correct items populateNavDrawer(); // When the user runs the app for the first time, we want to land them with the // navigation drawer open. But just the first time. if (!PrefUtils.isWelcomeDone(this)) { // first run of the app starts with the nav drawer open PrefUtils.markWelcomeDone(this); mDrawerLayout.openDrawer(Gravity.START); this.startService( new Intent(UpdateMatchService.ACTION_UPDATE_MATCHES, null, this, UpdateMatchService.class)); } if (TimeUtils.getUTCTime() - PrefUtils.lastMatchUpdate(this) > 60000 * 60 * 12) { this.startService(new Intent(UpdateMatchService.ACTION_SCHEDULE_AUTO_UPDATE, null, this, UpdateMatchService.class)); } } @Override public void setContentView(int layoutResID) { super.setContentView(layoutResID); getActionBarToolbar(); } protected void onNavDrawerStateChanged(boolean isOpen, boolean isAnimating) { if (mActionBarAutoHideEnabled && isOpen) { autoShowOrHideActionBar(true); } } protected void onNavDrawerSlide(float offset) { } protected boolean isNavDrawerOpen() { return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(Gravity.START); } private void populateNavDrawer() { mNavDrawerItems.clear(); mNavDrawerItems.add(NAVDRAWER_ITEM_MATCHES); mNavDrawerItems.add(NAVDRAWER_ITEM_TEAMS); //mNavDrawerItems.add(NAVDRAWER_ITEM_TOURNAMENTS); //mNavDrawerItems.add(NAVDRAWER_ITEM_NEWS); mNavDrawerItems.add(NAVDRAWER_ITEM_SEPARATOR); mNavDrawerItems.add(NAVDRAWER_ITEM_SETTINGS); createNavDrawerItems(); } private void createNavDrawerItems() { mDrawerItemsListContainer = (ViewGroup) findViewById(R.id.navdrawer_items_list); if (mDrawerItemsListContainer == null) { return; } mNavDrawerItemViews = new View[mNavDrawerItems.size()]; mDrawerItemsListContainer.removeAllViews(); int i = 0; for (int itemId : mNavDrawerItems) { mNavDrawerItemViews[i] = makeNavDrawerItem(itemId, mDrawerItemsListContainer); mDrawerItemsListContainer.addView(mNavDrawerItemViews[i]); ++i; } } private void setSelectedNavDrawerItem(int itemId) { if (mNavDrawerItemViews != null) { for (int i = 0; i < mNavDrawerItemViews.length; i++) { if (i < mNavDrawerItems.size()) { int thisItemId = mNavDrawerItems.get(i); formatNavDrawerItem(mNavDrawerItemViews[i], thisItemId, itemId == thisItemId); } } } } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); setupNavDrawer(); trySetupSwipeRefresh(); updateSwipeRefreshProgressBarTop(); // View mainContent = findViewById(R.id.main_content); // if (mainContent != null) { // mainContent.setAlpha(0); // mainContent.animate().alpha(1).setDuration(MAIN_CONTENT_FADEIN_DURATION); // } else { // Log.w(TAG, "No view to fade in"); // } } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); switch (id) { case R.id.menu_about: HelpUtils.showAbout(this); return true; } return super.onOptionsItemSelected(item); } private void goToNavDrawerItem(int item) { Intent intent; switch (item) { case NAVDRAWER_ITEM_MATCHES: intent = new Intent(this, MatchActivity.class); startActivity(intent); finish(); break; case NAVDRAWER_ITEM_TEAMS: intent = new Intent(this, TeamActivity.class); startActivity(intent); finish(); break; case NAVDRAWER_ITEM_TOURNAMENTS: Toast.makeText(this, "Not yet implemented", Toast.LENGTH_SHORT); break; // intent = new Intent(this, LiveGameStatsActivity.class); // startActivity(intent); // finish(); // break; case NAVDRAWER_ITEM_NEWS: Toast.makeText(this, "Not yet implemented", Toast.LENGTH_SHORT); break; // intent = new Intent(this, NewsActivity.class); // startActivity(intent); // finish(); // break; case NAVDRAWER_ITEM_SETTINGS: // Toast.makeText(this, "Not yet implemented", Toast.LENGTH_SHORT); intent = new Intent(this, SettingsActivity.class); startActivity(intent); break; } } private void onNavDrawerItemClicked(final int itemId) { if (itemId == getSelfNavDrawerItem()) { mDrawerLayout.closeDrawer(Gravity.START); return; } mHandler.postDelayed(new Runnable() { @Override public void run() { goToNavDrawerItem(itemId); } }, NAVDRAWER_LAUNCH_DELAY); setSelectedNavDrawerItem(itemId); View mainContent = findViewById(R.id.main_content); if (mainContent != null) { //mainContent.animate().alpha(0).setDuration(MAIN_CONTENT_FADEOUT_DURATION); } mDrawerLayout.closeDrawer(Gravity.START); } protected void setTabChanged() { tabChanged = true; } @Override protected void onResume() { super.onResume(); } @Override protected void onPause() { super.onPause(); } @Override protected void onStart() { super.onStart(); } /** * Initializes the Action Bar auto-hide (aka Quick Recall) effect. */ private void initActionBarAutoHide() { mActionBarAutoHideEnabled = true; mActionBarAutoHideMinY = getResources().getDimensionPixelOffset(R.dimen.action_bar_auto_hide_min_y); mActionBarAutoHideSensitivity = getResources() .getDimensionPixelOffset(R.dimen.action_bar_auto_hide_sensitivity); } /** * Indicates that the main content has scrolled (for the purposes of showing/hiding * the action bar for the "action bar auto hide" effect). currentY and deltaY may be exact * (if the underlying view supports it) or may be approximate indications: * deltaY may be INT_MAX to mean "scrolled forward indeterminately" and INT_MIN to mean * "scrolled backward indeterminately". currentY may be 0 to mean "somewhere close to the * start of the list" and INT_MAX to mean "we don't know, but not at the start of the list" */ private void onMainContentScrolled(int currentY, int deltaY) { if (deltaY > mActionBarAutoHideSensitivity) { deltaY = mActionBarAutoHideSensitivity; } else if (deltaY < -mActionBarAutoHideSensitivity) { deltaY = -mActionBarAutoHideSensitivity; } if (Math.signum(deltaY) * Math.signum(mActionBarAutoHideSignal) < 0) { // deltaY is a motion opposite to the accumulated signal, so reset signal mActionBarAutoHideSignal = deltaY; } else { // add to accumulated signal mActionBarAutoHideSignal += deltaY; } boolean shouldShow = currentY < mActionBarAutoHideMinY || (mActionBarAutoHideSignal <= -mActionBarAutoHideSensitivity); autoShowOrHideActionBar(shouldShow); } protected Toolbar getActionBarToolbar() { if (mActionBarToolbar == null) { mActionBarToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar); if (mActionBarToolbar != null) { setSupportActionBar(mActionBarToolbar); } } return mActionBarToolbar; } protected void autoShowOrHideActionBar(boolean show) { if (show == mActionBarShown) { return; } mActionBarShown = show; onActionBarAutoShowOrHide(show); } protected void enableActionBarAutoHide(final ListView listView) { initActionBarAutoHide(); listView.setOnScrollListener(new AbsListView.OnScrollListener() { final static int ITEMS_THRESHOLD = 3; int lastFvi = 0; @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { onMainContentScrolled(firstVisibleItem <= ITEMS_THRESHOLD ? 0 : Integer.MAX_VALUE, lastFvi - firstVisibleItem > 0 ? Integer.MIN_VALUE : lastFvi == firstVisibleItem ? 0 : Integer.MAX_VALUE); lastFvi = firstVisibleItem; } }); } private View makeNavDrawerItem(final int itemId, ViewGroup container) { boolean selected = getSelfNavDrawerItem() == itemId; int layoutToInflate = 0; if (itemId == NAVDRAWER_ITEM_SEPARATOR) { layoutToInflate = R.layout.navdrawer_separator; } else { layoutToInflate = R.layout.navdrawer_item; } View view = getLayoutInflater().inflate(layoutToInflate, container, false); if (isSeparator(itemId)) { // we are done UIUtils.setAccessibilityIgnore(view); return view; } ImageView iconView = (ImageView) view.findViewById(R.id.icon); TextView titleView = (TextView) view.findViewById(R.id.title); int iconId = itemId >= 0 && itemId < NAVDRAWER_ICON_RES_ID.length ? NAVDRAWER_ICON_RES_ID[itemId] : 0; int titleId = itemId >= 0 && itemId < NAVDRAWER_TITLE_RES_ID.length ? NAVDRAWER_TITLE_RES_ID[itemId] : 0; // set icon and text iconView.setVisibility(iconId > 0 ? View.VISIBLE : View.GONE); if (iconId > 0) { iconView.setImageResource(iconId); } titleView.setText(getString(titleId)); formatNavDrawerItem(view, itemId, selected); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onNavDrawerItemClicked(itemId); } }); return view; } private boolean isSpecialItem(int itemId) { return itemId == NAVDRAWER_ITEM_SETTINGS; } private boolean isSeparator(int itemId) { return itemId == NAVDRAWER_ITEM_SEPARATOR; } private void formatNavDrawerItem(View view, int itemId, boolean selected) { if (isSeparator(itemId)) { // not applicable return; } ImageView iconView = (ImageView) view.findViewById(R.id.icon); TextView titleView = (TextView) view.findViewById(R.id.title); // configure its appearance according to whether or not it's selected titleView.setTextColor(selected ? getResources().getColor(R.color.navdrawer_text_color_selected) : getResources().getColor(R.color.navdrawer_text_color)); iconView.setColorFilter(selected ? getResources().getColor(R.color.navdrawer_icon_tint_selected) : getResources().getColor(R.color.navdrawer_icon_tint)); } @Override protected void onDestroy() { super.onDestroy(); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); sp.unregisterOnSharedPreferenceChangeListener(this); } protected void onRefreshingStateChanged(boolean refreshing) { if (mSwipeRefreshLayout != null) { mSwipeRefreshLayout.setRefreshing(refreshing); } } protected void enableDisableSwipeRefresh(boolean enable) { if (mSwipeRefreshLayout != null) { mSwipeRefreshLayout.setEnabled(enable); } } protected void registerHideableHeaderView(View hideableHeaderView) { if (!mHideableHeaderViews.contains(hideableHeaderView)) { mHideableHeaderViews.add(hideableHeaderView); } } protected void deregisterHideableHeaderView(View hideableHeaderView) { if (mHideableHeaderViews.contains(hideableHeaderView)) { mHideableHeaderViews.remove(hideableHeaderView); } } public LUtils getLUtils() { return mLUtils; } public int getThemedStatusBarColor() { return mThemedStatusBarColor; } public void setNormalStatusBarColor(int color) { mNormalStatusBarColor = color; if (mDrawerLayout != null) { mDrawerLayout.setStatusBarBackgroundColor(mNormalStatusBarColor); } } protected void onActionBarAutoShowOrHide(boolean shown) { if (mStatusBarColorAnimator != null) { mStatusBarColorAnimator.cancel(); } mStatusBarColorAnimator = ObjectAnimator .ofInt((mDrawerLayout != null) ? mDrawerLayout : mLUtils, (mDrawerLayout != null) ? "statusBarBackgroundColor" : "statusBarColor", shown ? Color.BLACK : mNormalStatusBarColor, shown ? mNormalStatusBarColor : Color.BLACK) .setDuration(250); if (mDrawerLayout != null) { mStatusBarColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { ViewCompat.postInvalidateOnAnimation(mDrawerLayout); } }); } mStatusBarColorAnimator.setEvaluator(ARGB_EVALUATOR); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.L) { mStatusBarColorAnimator.start(); } updateSwipeRefreshProgressBarTop(); for (View view : mHideableHeaderViews) { if (shown) { view.animate().translationY(0).alpha(1).setDuration(HEADER_HIDE_ANIM_DURATION) .setInterpolator(new DecelerateInterpolator()); } else { view.animate().translationY(-UIUtils.calculateActionBarSize(this)).alpha(1) .setDuration(HEADER_HIDE_ANIM_DURATION).setInterpolator(new DecelerateInterpolator()); } } } @Override public boolean canSwipeRefreshChildScrollUp() { return false; } }