Java tutorial
/* * Twidere - Twitter client for Android * * Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.mariotaku.twidere.activity.support; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.SearchManager; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Canvas; import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.NotificationCompat; import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.support.v7.app.ThemedAppCompatDelegateFactory; import android.support.v7.widget.Toolbar; import android.view.Gravity; import android.view.KeyEvent; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.view.ViewGroup.MarginLayoutParams; import android.view.Window; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.FrameLayout.LayoutParams; import android.widget.Toast; import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu; import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu.CanvasTransformer; import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu.OnClosedListener; import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu.OnOpenedListener; import com.meizu.flyme.reflect.StatusBarProxy; import com.squareup.otto.Bus; import com.squareup.otto.Subscribe; import org.apache.commons.lang3.ArrayUtils; import org.mariotaku.twidere.R; import org.mariotaku.twidere.activity.SettingsActivity; import org.mariotaku.twidere.activity.SettingsWizardActivity; import org.mariotaku.twidere.activity.UsageStatisticsActivity; import org.mariotaku.twidere.adapter.support.SupportTabsAdapter; import org.mariotaku.twidere.app.TwidereApplication; import org.mariotaku.twidere.fragment.CustomTabsFragment; import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface; import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback; import org.mariotaku.twidere.fragment.support.AccountsDashboardFragment; import org.mariotaku.twidere.fragment.support.DirectMessagesFragment; import org.mariotaku.twidere.fragment.support.TrendsSuggestionsFragment; import org.mariotaku.twidere.graphic.EmptyDrawable; import org.mariotaku.twidere.model.ParcelableAccount; import org.mariotaku.twidere.model.SupportTabSpec; import org.mariotaku.twidere.provider.TwidereDataStore.Accounts; import org.mariotaku.twidere.provider.TwidereDataStore.Mentions; import org.mariotaku.twidere.provider.TwidereDataStore.Statuses; import org.mariotaku.twidere.service.StreamingService; import org.mariotaku.twidere.util.AsyncTaskUtils; import org.mariotaku.twidere.util.AsyncTwitterWrapper; import org.mariotaku.twidere.util.CustomTabUtils; import org.mariotaku.twidere.util.KeyboardShortcutsHandler; import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback; import org.mariotaku.twidere.util.MathUtils; import org.mariotaku.twidere.util.MultiSelectEventHandler; import org.mariotaku.twidere.util.ParseUtils; import org.mariotaku.twidere.util.ReadStateManager; import org.mariotaku.twidere.util.ThemeUtils; import org.mariotaku.twidere.util.TwidereColorUtils; import org.mariotaku.twidere.util.Utils; import org.mariotaku.twidere.util.message.TaskStateChangedEvent; import org.mariotaku.twidere.util.message.UnreadCountUpdatedEvent; import org.mariotaku.twidere.util.support.ActivitySupport; import org.mariotaku.twidere.util.support.ActivitySupport.TaskDescriptionCompat; import org.mariotaku.twidere.util.support.ViewSupport; import org.mariotaku.twidere.util.support.view.ViewOutlineProviderCompat; import org.mariotaku.twidere.view.ExtendedViewPager; import org.mariotaku.twidere.view.HomeSlidingMenu; import org.mariotaku.twidere.view.LeftDrawerFrameLayout; import org.mariotaku.twidere.view.TabPagerIndicator; import org.mariotaku.twidere.view.TintedStatusFrameLayout; import org.mariotaku.twidere.view.iface.IHomeActionButton; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import edu.tsinghua.spice.Utilies.NetworkStateUtil; import edu.tsinghua.spice.Utilies.SpiceProfilingUtil; import static org.mariotaku.twidere.util.CompareUtils.classEquals; import static org.mariotaku.twidere.util.Utils.cleanDatabasesByItemLimit; import static org.mariotaku.twidere.util.Utils.getDefaultAccountId; import static org.mariotaku.twidere.util.Utils.getTabDisplayOptionInt; import static org.mariotaku.twidere.util.Utils.isDatabaseReady; import static org.mariotaku.twidere.util.Utils.openMessageConversation; import static org.mariotaku.twidere.util.Utils.openSearch; import static org.mariotaku.twidere.util.Utils.showMenuItemToast; public class HomeActivity extends BaseAppCompatActivity implements OnClickListener, OnPageChangeListener, SupportFragmentCallback, OnOpenedListener, OnClosedListener, OnLongClickListener { private final Handler mHandler = new Handler(); private final ContentObserver mAccountChangeObserver = new AccountChangeObserver(this, mHandler); private ParcelableAccount mSelectedAccountToSearch; private SharedPreferences mPreferences; private AsyncTwitterWrapper mTwitterWrapper; private NotificationManager mNotificationManager; private MultiSelectEventHandler mMultiSelectHandler; private ReadStateManager mReadStateManager; private SupportTabsAdapter mPagerAdapter; private ExtendedViewPager mViewPager; private TabPagerIndicator mTabIndicator; private HomeSlidingMenu mSlidingMenu; private View mEmptyTabHint; private View mActionsButton; private View mActionBarWithOverlay; private LeftDrawerFrameLayout mLeftDrawerContainer; private TintedStatusFrameLayout mColorStatusFrameLayout; private UpdateUnreadCountTask mUpdateUnreadCountTask; private Toolbar mActionBar; private OnSharedPreferenceChangeListener mReadStateChangeListener = new OnSharedPreferenceChangeListener() { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { updateUnreadCount(); } }; private ControlBarShowHideHelper mControlBarShowHideHelper = new ControlBarShowHideHelper(this); private int mTabColumns; private View mActionBarContainer; public void closeAccountsDrawer() { if (mSlidingMenu == null) return; mSlidingMenu.showContent(); } public long[] getActivatedAccountIds() { final Fragment fragment = getLeftDrawerFragment(); if (fragment instanceof AccountsDashboardFragment) { return ((AccountsDashboardFragment) fragment).getActivatedAccountIds(); } return Utils.getActivatedAccountIds(this); } @Override public Fragment getCurrentVisibleFragment() { final int currentItem = mViewPager.getCurrentItem(); if (currentItem < 0 || currentItem >= mPagerAdapter.getCount()) return null; return (Fragment) mPagerAdapter.instantiateItem(mViewPager, currentItem); } @Override public boolean triggerRefresh(final int position) { final Fragment f = (Fragment) mPagerAdapter.instantiateItem(mViewPager, position); if (!(f instanceof RefreshScrollTopInterface)) return false; if (f.getActivity() == null || f.isDetached()) return false; return ((RefreshScrollTopInterface) f).triggerRefresh(); } public Fragment getLeftDrawerFragment() { return getSupportFragmentManager().findFragmentById(R.id.left_drawer); } @Override public boolean getSystemWindowsInsets(Rect insets) { final int height = mTabIndicator != null ? mTabIndicator.getHeight() : 0; insets.top = height != 0 ? height : ThemeUtils.getActionBarHeight(this); return true; } @Override public void setControlBarVisibleAnimate(boolean visible) { mControlBarShowHideHelper.setControlBarVisibleAnimate(visible); } @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case MENU_HOME: { final FragmentManager fm = getSupportFragmentManager(); final int count = fm.getBackStackEntryCount(); if (mSlidingMenu.isMenuShowing()) { mSlidingMenu.showContent(); return true; } else if (count == 0) { mSlidingMenu.showMenu(); return true; } return true; } case MENU_SEARCH: { openSearchView(mSelectedAccountToSearch); return true; } case MENU_ACTIONS: { triggerActionsClick(); return true; } } return super.onOptionsItemSelected(item); } @Override public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event) { if (handleFragmentKeyboardShortcutSingle(handler, keyCode, event)) return true; String action = handler.getKeyAction(CONTEXT_TAG_HOME, keyCode, event); if (action != null) { switch (action) { case ACTION_HOME_ACCOUNTS_DASHBOARD: { if (mSlidingMenu.isMenuShowing()) { mSlidingMenu.showContent(true); } else { mSlidingMenu.showMenu(true); setControlBarVisibleAnimate(true); } return true; } } } action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event); if (action != null) { switch (action) { case ACTION_NAVIGATION_PREVIOUS_TAB: { final int previous = mViewPager.getCurrentItem() - 1; final int mode = mSlidingMenu.getMode(); if (previous < 0 && (mode == SlidingMenu.LEFT || mode == SlidingMenu.LEFT_RIGHT)) { mSlidingMenu.showMenu(true); setControlBarVisibleAnimate(true); } else if (previous < mPagerAdapter.getCount()) { if (mSlidingMenu.isSecondaryMenuShowing()) { mSlidingMenu.showContent(true); } else { mViewPager.setCurrentItem(previous, true); } } return true; } case ACTION_NAVIGATION_NEXT_TAB: { final int next = mViewPager.getCurrentItem() + 1; final int mode = mSlidingMenu.getMode(); if (next >= mPagerAdapter.getCount() && (mode == SlidingMenu.RIGHT || mode == SlidingMenu.LEFT_RIGHT)) { mSlidingMenu.showSecondaryMenu(true); setControlBarVisibleAnimate(true); } else if (next >= 0) { if (mSlidingMenu.isMenuShowing()) { mSlidingMenu.showContent(true); } else { mViewPager.setCurrentItem(next, true); } } return true; } } } return handler.handleKey(this, null, keyCode, event); } @Override public void setControlBarOffset(float offset) { mActionBarWithOverlay.setTranslationY(mTabColumns > 1 ? 0 : getControlBarHeight() * (offset - 1)); final ViewGroup.LayoutParams lp = mActionsButton.getLayoutParams(); if (lp instanceof MarginLayoutParams) { mActionsButton.setTranslationY( (((MarginLayoutParams) lp).bottomMargin + mActionsButton.getHeight()) * (1 - offset)); } else { mActionsButton.setTranslationY(mActionsButton.getHeight() * (1 - offset)); } notifyControlBarOffsetChanged(); } @Override public boolean handleKeyboardShortcutRepeat(@NonNull KeyboardShortcutsHandler handler, int keyCode, int repeatCount, @NonNull KeyEvent event) { if (handleFragmentKeyboardShortcutRepeat(handler, keyCode, repeatCount, event)) return true; return super.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event); } /** * Called when the context is first created. */ @Override protected void onCreate(final Bundle savedInstanceState) { final Window window = getWindow(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } super.onCreate(savedInstanceState); if (!isDatabaseReady(this)) { Toast.makeText(this, R.string.preparing_database_toast, Toast.LENGTH_SHORT).show(); finish(); return; } mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); mTwitterWrapper = getTwitterWrapper(); final TwidereApplication app = TwidereApplication.getInstance(this); mReadStateManager = app.getReadStateManager(); mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); mMultiSelectHandler = new MultiSelectEventHandler(this); mMultiSelectHandler.dispatchOnCreate(); // if (!Utils.hasAccount(this)) { // final Intent signInIntent = new Intent(INTENT_ACTION_TWITTER_LOGIN); // signInIntent.setClass(this, SignInActivity.class); // startActivity(signInIntent); // finish(); // return; // } else { // notifyAccountsChanged(); // } final Intent intent = getIntent(); if (openSettingsWizard()) { finish(); return; } setContentView(R.layout.activity_home); setSupportActionBar(mActionBar); sendBroadcast(new Intent(BROADCAST_HOME_ACTIVITY_ONCREATE)); final boolean refreshOnStart = mPreferences.getBoolean(KEY_REFRESH_ON_START, false); int tabDisplayOptionInt = getTabDisplayOptionInt(this); mTabColumns = getResources().getInteger(R.integer.default_tab_columns); mColorStatusFrameLayout.setOnFitSystemWindowsListener(this); mPagerAdapter = new SupportTabsAdapter(this, getSupportFragmentManager(), mTabIndicator, mTabColumns); mViewPager.setAdapter(mPagerAdapter); // mViewPager.setOffscreenPageLimit(3); mTabIndicator.setViewPager(mViewPager); mTabIndicator.setOnPageChangeListener(this); mTabIndicator.setColumns(mTabColumns); if (tabDisplayOptionInt == 0) { tabDisplayOptionInt = TabPagerIndicator.ICON; } mTabIndicator.setTabDisplayOption(tabDisplayOptionInt); mTabIndicator.setTabExpandEnabled((tabDisplayOptionInt & TabPagerIndicator.LABEL) == 0); mTabIndicator.setDisplayBadge(mPreferences.getBoolean(KEY_UNREAD_COUNT, true)); mTabIndicator.updateAppearance(); mActionsButton.setOnClickListener(this); mActionsButton.setOnLongClickListener(this); mEmptyTabHint.setOnClickListener(this); ThemeUtils.setCompatContentViewOverlay(this, new EmptyDrawable()); ViewCompat.setElevation(mActionBarContainer, ThemeUtils.getSupportActionBarElevation(this)); ViewSupport.setOutlineProvider(mActionBarContainer, ViewOutlineProviderCompat.BACKGROUND); final View windowOverlay = findViewById(R.id.window_overlay); ViewSupport.setBackground(windowOverlay, ThemeUtils.getNormalWindowContentOverlay(this, getCurrentThemeResourceId())); setupSlidingMenu(); setupBars(); showDataProfilingRequest(); initUnreadCount(); updateActionsButton(); updateSlidingMenuTouchMode(); getDelegate().setKeyListener(new ThemedAppCompatDelegateFactory.KeyListener() { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return false; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { // Steal MENU key event switch (keyCode) { case KeyEvent.KEYCODE_MENU: { if (mSlidingMenu != null) { mSlidingMenu.toggle(true); return true; } break; } } return false; } }); if (savedInstanceState == null) { if (refreshOnStart) { mTwitterWrapper.refreshAll(getActivatedAccountIds()); } if (intent.getBooleanExtra(EXTRA_OPEN_ACCOUNTS_DRAWER, false)) { openAccountsDrawer(); } } setupHomeTabs(); final int initialTabPosition = handleIntent(intent, savedInstanceState == null); setTabPosition(initialTabPosition); startService(new Intent(this, StreamingService.class)); } @Override protected void onStart() { super.onStart(); mMultiSelectHandler.dispatchOnStart(); sendBroadcast(new Intent(BROADCAST_HOME_ACTIVITY_ONSTART)); final ContentResolver resolver = getContentResolver(); resolver.registerContentObserver(Accounts.CONTENT_URI, true, mAccountChangeObserver); final Bus bus = TwidereApplication.getInstance(this).getMessageBus(); assert bus != null; bus.register(this); // spice SpiceProfilingUtil.profile(this, SpiceProfilingUtil.FILE_NAME_APP, "App Launch" + "," + Build.MODEL + "," + "mediaPreview=" + mPreferences.getBoolean(KEY_MEDIA_PREVIEW, false)); SpiceProfilingUtil.profile(this, SpiceProfilingUtil.FILE_NAME_ONLAUNCH, "App Launch" + "," + NetworkStateUtil.getConnectedType(this) + "," + Build.MODEL); //end mReadStateManager.registerOnSharedPreferenceChangeListener(mReadStateChangeListener); updateUnreadCount(); } @Override protected void onResume() { super.onResume(); sendBroadcast(new Intent(BROADCAST_HOME_ACTIVITY_ONRESUME)); invalidateOptionsMenu(); updateActionsButtonStyle(); updateActionsButton(); updateSlidingMenuTouchMode(); } @Override protected void onPause() { sendBroadcast(new Intent(BROADCAST_HOME_ACTIVITY_ONPAUSE)); super.onPause(); } @Override protected void onStop() { mMultiSelectHandler.dispatchOnStop(); mReadStateManager.unregisterOnSharedPreferenceChangeListener(mReadStateChangeListener); final Bus bus = TwidereApplication.getInstance(this).getMessageBus(); assert bus != null; bus.unregister(this); final ContentResolver resolver = getContentResolver(); resolver.unregisterContentObserver(mAccountChangeObserver); mPreferences.edit().putInt(KEY_SAVED_TAB_POSITION, mViewPager.getCurrentItem()).apply(); sendBroadcast(new Intent(BROADCAST_HOME_ACTIVITY_ONSTOP)); // spice SpiceProfilingUtil.profile(this, SpiceProfilingUtil.FILE_NAME_APP, "App Stop"); SpiceProfilingUtil.profile(this, SpiceProfilingUtil.FILE_NAME_ONLAUNCH, "App Stop" + "," + NetworkStateUtil.getConnectedType(this) + "," + Build.MODEL); //end super.onStop(); } public ViewPager getViewPager() { return mViewPager; } public void notifyAccountsChanged() { } @Subscribe public void notifyTaskStateChanged(TaskStateChangedEvent event) { updateActionsButton(); } @Subscribe public void notifyUnreadCountUpdated(UnreadCountUpdatedEvent event) { updateUnreadCount(); } @Override public void onClick(final View v) { switch (v.getId()) { case R.id.actions_button: { triggerActionsClick(); break; } case R.id.empty_tab_hint: { final Intent intent = new Intent(this, SettingsActivity.class); intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, CustomTabsFragment.class.getName()); intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, R.string.tabs); startActivityForResult(intent, REQUEST_SETTINGS); break; } } } @Override public void onClosed() { updateDrawerPercentOpen(0, true); } @Override public boolean onLongClick(final View v) { switch (v.getId()) { case R.id.actions_button: { showMenuItemToast(v, v.getContentDescription(), true); return true; } } return false; } @Override public void onOpened() { updateDrawerPercentOpen(1, true); } @Override public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) { } @Override public void onPageSelected(final int position) { if (mSlidingMenu.isMenuShowing()) { mSlidingMenu.showContent(); } updateSlidingMenuTouchMode(); updateActionsButton(); } @Override public void onPageScrollStateChanged(final int state) { setControlBarVisibleAnimate(true); } @Override public void onWindowFocusChanged(final boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (mSlidingMenu != null && mSlidingMenu.isMenuShowing()) { updateDrawerPercentOpen(1, false); } else { updateDrawerPercentOpen(0, false); } } @Override public boolean onSearchRequested() { startActivity(new Intent(this, QuickSearchBarActivity.class)); return true; } public void openSearchView(final ParcelableAccount account) { mSelectedAccountToSearch = account; onSearchRequested(); } public void setSystemWindowInsets(Rect insets) { final Fragment fragment = getLeftDrawerFragment(); if (fragment instanceof AccountsDashboardFragment) { ((AccountsDashboardFragment) fragment).setStatusBarHeight(insets.top); } mColorStatusFrameLayout.setStatusBarHeight(insets.top); } public void updateUnreadCount() { if (mTabIndicator == null || mUpdateUnreadCountTask != null && mUpdateUnreadCountTask.getStatus() == AsyncTask.Status.RUNNING) return; mUpdateUnreadCountTask = new UpdateUnreadCountTask(this, mReadStateManager, mTabIndicator, mPagerAdapter.getTabs()); AsyncTaskUtils.executeTask(mUpdateUnreadCountTask); mTabIndicator.setDisplayBadge(mPreferences.getBoolean(KEY_UNREAD_COUNT, true)); } @Override protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { switch (requestCode) { case REQUEST_SWIPEBACK_ACTIVITY: { // closeAccountsDrawer(); return; } } super.onActivityResult(requestCode, resultCode, data); } @Override protected void onNewIntent(final Intent intent) { final int tabPosition = handleIntent(intent, false); if (tabPosition >= 0) { mViewPager.setCurrentItem(MathUtils.clamp(tabPosition, mPagerAdapter.getCount(), 0)); } } @Override protected void onDestroy() { stopService(new Intent(this, StreamingService.class)); // Delete unused items in databases. cleanDatabasesByItemLimit(this); sendBroadcast(new Intent(BROADCAST_HOME_ACTIVITY_ONDESTROY)); super.onDestroy(); } @Override public void onBackPressed() { if (mSlidingMenu != null && mSlidingMenu.isMenuShowing()) { mSlidingMenu.showContent(); return; } super.onBackPressed(); } @Override public float getControlBarOffset() { if (mTabColumns > 1) { final ViewGroup.LayoutParams lp = mActionsButton.getLayoutParams(); float total; if (lp instanceof MarginLayoutParams) { total = ((MarginLayoutParams) lp).bottomMargin + mActionsButton.getHeight(); } else { total = mActionsButton.getHeight(); } return 1 - mActionsButton.getTranslationY() / total; } final float totalHeight = getControlBarHeight(); return 1 + mActionBarWithOverlay.getTranslationY() / totalHeight; } @Override public void onContentChanged() { super.onContentChanged(); mActionBar = (Toolbar) findViewById(R.id.action_bar); mActionBarContainer = findViewById(R.id.twidere_action_bar_container); mTabIndicator = (TabPagerIndicator) findViewById(R.id.main_tabs); mSlidingMenu = (HomeSlidingMenu) findViewById(R.id.home_menu); mViewPager = (ExtendedViewPager) findViewById(R.id.main_pager); mEmptyTabHint = findViewById(R.id.empty_tab_hint); mActionsButton = findViewById(R.id.actions_button); mActionBarWithOverlay = findViewById(R.id.twidere_action_bar_with_overlay); mTabIndicator = (TabPagerIndicator) findViewById(R.id.main_tabs); mColorStatusFrameLayout = (TintedStatusFrameLayout) findViewById(R.id.home_content); } private Fragment getKeyboardShortcutRecipient() { if (mSlidingMenu.isMenuShowing()) { return getLeftDrawerFragment(); } else if (mSlidingMenu.isSecondaryMenuShowing()) { return null; } else { return getCurrentVisibleFragment(); } } @Override public int getControlBarHeight() { return mTabIndicator.getHeight() - mTabIndicator.getStripHeight(); } private boolean handleFragmentKeyboardShortcutRepeat(final KeyboardShortcutsHandler handler, final int keyCode, final int repeatCount, @NonNull final KeyEvent event) { final Fragment fragment = getKeyboardShortcutRecipient(); if (fragment instanceof KeyboardShortcutCallback) { return ((KeyboardShortcutCallback) fragment).handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event); } return false; } private boolean handleFragmentKeyboardShortcutSingle(final KeyboardShortcutsHandler handler, final int keyCode, @NonNull final KeyEvent event) { final Fragment fragment = getKeyboardShortcutRecipient(); if (fragment instanceof KeyboardShortcutCallback) { return ((KeyboardShortcutCallback) fragment).handleKeyboardShortcutSingle(handler, keyCode, event); } return false; } private int handleIntent(final Intent intent, final boolean firstCreate) { // use packge's class loader to prevent BadParcelException intent.setExtrasClassLoader(getClassLoader()); // reset intent setIntent(new Intent(this, HomeActivity.class)); final String action = intent.getAction(); if (Intent.ACTION_SEARCH.equals(action)) { final String query = intent.getStringExtra(SearchManager.QUERY); final Bundle appSearchData = intent.getBundleExtra(SearchManager.APP_DATA); final long accountId; if (appSearchData != null && appSearchData.containsKey(EXTRA_ACCOUNT_ID)) { accountId = appSearchData.getLong(EXTRA_ACCOUNT_ID, -1); } else { accountId = getDefaultAccountId(this); } openSearch(this, accountId, query); return -1; } final boolean refreshOnStart = mPreferences.getBoolean(KEY_REFRESH_ON_START, false); final long[] refreshedIds = intent.getLongArrayExtra(EXTRA_REFRESH_IDS); if (refreshedIds != null) { mTwitterWrapper.refreshAll(refreshedIds); } else if (firstCreate && refreshOnStart) { mTwitterWrapper.refreshAll(); } final Uri uri = intent.getData(); final String tabType = uri != null ? Utils.matchTabType(uri) : null; int initialTab = -1; if (tabType != null) { final long accountId = ParseUtils.parseLong(uri.getQueryParameter(QUERY_PARAM_ACCOUNT_ID)); for (int i = mPagerAdapter.getCount() - 1; i > -1; i--) { final SupportTabSpec tab = mPagerAdapter.getTab(i); if (tabType.equals(tab.type)) { initialTab = i; if (hasAccountId(tab.args, accountId)) { break; } } } } if (initialTab != -1 && mViewPager != null) { // clearNotification(initial_tab); } final Intent extraIntent = intent.getParcelableExtra(EXTRA_EXTRA_INTENT); if (extraIntent != null && firstCreate) { extraIntent.setExtrasClassLoader(getClassLoader()); startActivity(extraIntent); } return initialTab; } private boolean hasAccountId(Bundle args, long accountId) { if (args == null) return false; if (args.containsKey(EXTRA_ACCOUNT_ID)) { return args.getLong(EXTRA_ACCOUNT_ID) == accountId; } else if (args.containsKey(EXTRA_ACCOUNT_IDS)) { return ArrayUtils.contains(args.getLongArray(EXTRA_ACCOUNT_IDS), accountId); } return false; } private void initUnreadCount() { for (int i = 0, j = mTabIndicator.getCount(); i < j; i++) { mTabIndicator.setBadge(i, 0); } } private void openAccountsDrawer() { if (mSlidingMenu == null) return; mSlidingMenu.showMenu(); } private boolean openSettingsWizard() { if (mPreferences == null || mPreferences.getBoolean(KEY_SETTINGS_WIZARD_COMPLETED, false)) return false; startActivity(new Intent(this, SettingsWizardActivity.class)); return true; } private void setTabPosition(final int initialTab) { final boolean rememberPosition = mPreferences.getBoolean(KEY_REMEMBER_POSITION, true); if (initialTab >= 0) { mViewPager.setCurrentItem(MathUtils.clamp(initialTab, mPagerAdapter.getCount(), 0)); } else if (rememberPosition) { final int position = mPreferences.getInt(KEY_SAVED_TAB_POSITION, 0); mViewPager.setCurrentItem(MathUtils.clamp(position, mPagerAdapter.getCount(), 0)); } } private void setupBars() { final int themeColor = getThemeColor(); final int themeResId = getCurrentThemeResourceId(); final String backgroundOption = getCurrentThemeBackgroundOption(); final boolean isTransparent = ThemeUtils.isTransparentBackground(backgroundOption); final int actionBarAlpha = isTransparent ? ThemeUtils.getActionBarAlpha(ThemeUtils.getUserThemeBackgroundAlpha(this)) : 0xFF; final IHomeActionButton homeActionButton = (IHomeActionButton) mActionsButton; mTabIndicator.setItemContext(ThemeUtils.getActionBarThemedContext(this, themeResId, themeColor)); ViewSupport.setBackground(mActionBarContainer, ThemeUtils.getActionBarBackground(this, themeResId, themeColor, backgroundOption, true)); final int actionBarColor = ThemeUtils.getActionBarColor(this, themeColor, themeResId, backgroundOption); final int actionItemColor = ThemeUtils.getContrastForegroundColor(this, getCurrentThemeResourceId(), themeColor); final int[] foregroundColors = new int[2]; ThemeUtils.getColorForegroundAndInverse(this, foregroundColors); if (ThemeUtils.isDarkTheme(themeResId)) { homeActionButton.setButtonColor(actionBarColor); homeActionButton.setIconColor(actionItemColor, Mode.SRC_ATOP); mTabIndicator.setStripColor(themeColor); mTabIndicator.setIconColor(foregroundColors[0]); mTabIndicator.setLabelColor(foregroundColors[0]); } else { final int contrastColor = TwidereColorUtils.getContrastYIQ(themeColor, ThemeUtils.ACCENT_COLOR_THRESHOLD, foregroundColors[0], foregroundColors[1]); homeActionButton.setButtonColor(themeColor); homeActionButton.setIconColor(actionItemColor, Mode.SRC_ATOP); mTabIndicator.setStripColor(contrastColor); mTabIndicator.setIconColor(contrastColor); mTabIndicator.setLabelColor(contrastColor); ActivitySupport.setTaskDescription(this, new TaskDescriptionCompat(null, null, themeColor)); } mColorStatusFrameLayout.setDrawColor(true); mColorStatusFrameLayout.setDrawShadow(false); mColorStatusFrameLayout.setColor(actionBarColor, actionBarAlpha); StatusBarProxy.setStatusBarDarkIcon(getWindow(), TwidereColorUtils.getYIQLuminance(actionBarColor) > ThemeUtils.ACCENT_COLOR_THRESHOLD); mColorStatusFrameLayout.setFactor(1); mActionBarWithOverlay.setAlpha(actionBarAlpha / 255f); mActionsButton.setAlpha(actionBarAlpha / 255f); } private void setupHomeTabs() { mPagerAdapter.clear(); mPagerAdapter.addTabs(CustomTabUtils.getHomeTabs(this)); final boolean hasNoTab = mPagerAdapter.getCount() == 0; mEmptyTabHint.setVisibility(hasNoTab ? View.VISIBLE : View.GONE); mViewPager.setVisibility(hasNoTab ? View.GONE : View.VISIBLE); // mViewPager.setOffscreenPageLimit(mPagerAdapter.getCount() / 2); } private void setupSlidingMenu() { if (mSlidingMenu == null) return; final Resources res = getResources(); final int marginThreshold = res.getDimensionPixelSize(R.dimen.default_sliding_menu_margin_threshold); final boolean relativeBehindWidth = res.getBoolean(R.bool.relative_behind_width); mSlidingMenu.setMode(SlidingMenu.LEFT); mSlidingMenu.setShadowWidthRes(R.dimen.default_sliding_menu_shadow_width); mSlidingMenu.setShadowDrawable(R.drawable.shadow_left); mSlidingMenu.setSecondaryShadowDrawable(R.drawable.shadow_right); if (relativeBehindWidth) { mSlidingMenu.setBehindOffsetRes(R.dimen.drawer_offset_home); } else { mSlidingMenu.setBehindWidthRes(R.dimen.drawer_width_home); } mSlidingMenu.setTouchmodeMarginThreshold(marginThreshold); mSlidingMenu.setFadeDegree(0.5f); mSlidingMenu.setMenu(R.layout.drawer_home_accounts); mSlidingMenu.setOnOpenedListener(this); mSlidingMenu.setOnClosedListener(this); mLeftDrawerContainer = (LeftDrawerFrameLayout) mSlidingMenu.getMenu() .findViewById(R.id.left_drawer_container); final boolean isTransparentBackground = ThemeUtils .isTransparentBackground(getCurrentThemeBackgroundOption()); mLeftDrawerContainer.setClipEnabled(isTransparentBackground); mLeftDrawerContainer.setScrollScale(mSlidingMenu.getBehindScrollScale()); mSlidingMenu.setBehindCanvasTransformer(new ListenerCanvasTransformer(this)); final Window window = getWindow(); ThemeUtils.applyWindowBackground(this, mSlidingMenu.getContent(), getCurrentThemeResourceId(), getThemeBackgroundOption(), getCurrentThemeBackgroundAlpha()); window.setBackgroundDrawable(new EmptyDrawable()); mSlidingMenu.addIgnoredView(mActionBarContainer); } private void showDataProfilingRequest() { //spice if (mPreferences.contains(KEY_USAGE_STATISTICS)) { return; } final Intent intent = new Intent(this, UsageStatisticsActivity.class); final PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0); final NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setAutoCancel(true); builder.setSmallIcon(R.drawable.ic_stat_info); builder.setTicker(getString(R.string.usage_statistics)); builder.setContentTitle(getString(R.string.usage_statistics)); builder.setContentText(getString(R.string.usage_statistics_notification_summary)); builder.setContentIntent(contentIntent); mNotificationManager.notify(NOTIFICATION_ID_DATA_PROFILING, builder.build()); } private void triggerActionsClick() { if (mViewPager == null || mPagerAdapter == null) return; final int position = mViewPager.getCurrentItem(); final SupportTabSpec tab = mPagerAdapter.getTab(position); if (tab == null) { startActivity(new Intent(INTENT_ACTION_COMPOSE)); } else { if (classEquals(DirectMessagesFragment.class, tab.cls)) { openMessageConversation(this, -1, -1); } else if (classEquals(TrendsSuggestionsFragment.class, tab.cls)) { openSearchView(null); } else { startActivity(new Intent(INTENT_ACTION_COMPOSE)); } } } private void updateActionsButton() { if (mViewPager == null || mPagerAdapter == null) return; final int icon, title; final int position = mViewPager.getCurrentItem(); final SupportTabSpec tab = mPagerAdapter.getTab(position); if (tab == null) { title = R.string.compose; icon = R.drawable.ic_action_status_compose; } else { if (classEquals(DirectMessagesFragment.class, tab.cls)) { icon = R.drawable.ic_action_add; title = R.string.new_direct_message; } else if (classEquals(TrendsSuggestionsFragment.class, tab.cls)) { icon = R.drawable.ic_action_search; title = android.R.string.search_go; } else { icon = R.drawable.ic_action_status_compose; title = R.string.compose; } } if (mActionsButton instanceof IHomeActionButton) { final IHomeActionButton hab = (IHomeActionButton) mActionsButton; hab.setIcon(icon); hab.setTitle(title); } } private void updateActionsButtonStyle() { final boolean leftsideComposeButton = mPreferences.getBoolean(KEY_LEFTSIDE_COMPOSE_BUTTON, false); final FrameLayout.LayoutParams lp = (LayoutParams) mActionsButton.getLayoutParams(); lp.gravity = Gravity.BOTTOM | (leftsideComposeButton ? Gravity.LEFT : Gravity.RIGHT); mActionsButton.setLayoutParams(lp); } private void updateDrawerPercentOpen(final float percentOpen, final boolean horizontalScroll) { if (mLeftDrawerContainer == null) return; mLeftDrawerContainer.setPercentOpen(percentOpen); } private void updateSlidingMenuTouchMode() { if (mViewPager == null || mSlidingMenu == null) return; final int position = mViewPager.getCurrentItem(); final boolean pagingEnabled = mViewPager.isEnabled(); final boolean atFirstOrLast = position == 0 || position == mPagerAdapter.getCount() - 1; final int mode = !pagingEnabled || atFirstOrLast ? SlidingMenu.TOUCHMODE_FULLSCREEN : SlidingMenu.TOUCHMODE_MARGIN; mSlidingMenu.setTouchModeAbove(mode); } private static final class AccountChangeObserver extends ContentObserver { private final HomeActivity mActivity; public AccountChangeObserver(final HomeActivity activity, final Handler handler) { super(handler); mActivity = activity; } @Override public void onChange(final boolean selfChange) { onChange(selfChange, null); } @Override public void onChange(final boolean selfChange, final Uri uri) { mActivity.notifyAccountsChanged(); mActivity.updateUnreadCount(); } } private static class ListenerCanvasTransformer implements CanvasTransformer { private final HomeActivity mHomeActivity; public ListenerCanvasTransformer(final HomeActivity homeActivity) { mHomeActivity = homeActivity; } @Override public void transformCanvas(final Canvas canvas, final float percentOpen) { mHomeActivity.updateDrawerPercentOpen(percentOpen, true); } } private static class UpdateUnreadCountTask extends AsyncTask<Object, Object, Map<SupportTabSpec, Integer>> { private final Context mContext; private final ReadStateManager mReadStateManager; private final TabPagerIndicator mIndicator; private final List<SupportTabSpec> mTabs; UpdateUnreadCountTask(final Context context, final ReadStateManager manager, final TabPagerIndicator indicator, final List<SupportTabSpec> tabs) { mContext = context; mReadStateManager = manager; mIndicator = indicator; mTabs = Collections.unmodifiableList(tabs); } @Override protected Map<SupportTabSpec, Integer> doInBackground(final Object... params) { final Map<SupportTabSpec, Integer> result = new HashMap<>(); for (SupportTabSpec spec : mTabs) { switch (spec.type) { case TAB_TYPE_HOME_TIMELINE: { final long[] accountIds = Utils.getAccountIds(spec.args); final String tagWithAccounts = Utils.getReadPositionTagWithAccounts(mContext, true, spec.tag, accountIds); final long position = mReadStateManager.getPosition(tagWithAccounts); result.put(spec, Utils.getStatusesCount(mContext, Statuses.CONTENT_URI, position, accountIds)); break; } case TAB_TYPE_MENTIONS_TIMELINE: { final long[] accountIds = Utils.getAccountIds(spec.args); final String tagWithAccounts = Utils.getReadPositionTagWithAccounts(mContext, true, spec.tag, accountIds); final long position = mReadStateManager.getPosition(tagWithAccounts); result.put(spec, Utils.getStatusesCount(mContext, Mentions.CONTENT_URI, position, accountIds)); break; } case TAB_TYPE_DIRECT_MESSAGES: { break; } } } return result; } @Override protected void onPostExecute(final Map<SupportTabSpec, Integer> result) { mIndicator.clearBadge(); for (Entry<SupportTabSpec, Integer> entry : result.entrySet()) { final SupportTabSpec key = entry.getKey(); mIndicator.setBadge(key.position, entry.getValue()); } } } }