diff options
Diffstat (limited to 'src/com/android/messaging/ui/BugleActionBarActivity.java')
-rw-r--r-- | src/com/android/messaging/ui/BugleActionBarActivity.java | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/src/com/android/messaging/ui/BugleActionBarActivity.java b/src/com/android/messaging/ui/BugleActionBarActivity.java new file mode 100644 index 0000000..80dabb8 --- /dev/null +++ b/src/com/android/messaging/ui/BugleActionBarActivity.java @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2015 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.android.messaging.ui; + +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.support.v7.app.ActionBar; +import android.support.v7.app.ActionBarActivity; +import android.view.ActionMode; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; + +import com.android.messaging.R; +import com.android.messaging.util.BugleActivityUtil; +import com.android.messaging.util.ImeUtil; +import com.android.messaging.util.LogUtil; +import com.android.messaging.util.UiUtils; + +import java.util.HashSet; +import java.util.Set; + +/** + * Base class for app activities that use an action bar. Responsible for logging/telemetry/other + * needs that will be common for all activities. We can break out the common code if/when we need + * a version that doesn't use an actionbar. + */ +public class BugleActionBarActivity extends ActionBarActivity implements ImeUtil.ImeStateHost { + // Tracks the list of observers opting in for IME state change. + private final Set<ImeUtil.ImeStateObserver> mImeStateObservers = new HashSet<>(); + + // Tracks the soft keyboard display state + private boolean mImeOpen; + + // The ActionMode that represents the modal contextual action bar, using our own implementation + // rather than the built in contextual action bar to reduce jank + private CustomActionMode mActionMode; + + // The menu for the action bar + private Menu mActionBarMenu; + + // Used to determine if a onDisplayHeightChanged was due to the IME opening or rotation of the + // device + private int mLastScreenHeight; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (UiUtils.redirectToPermissionCheckIfNeeded(this)) { + return; + } + + mLastScreenHeight = getResources().getDisplayMetrics().heightPixels; + if (LogUtil.isLoggable(LogUtil.BUGLE_TAG, LogUtil.VERBOSE)) { + LogUtil.v(LogUtil.BUGLE_TAG, this.getLocalClassName() + ".onCreate"); + } + } + + @Override + protected void onStart() { + super.onStart(); + if (LogUtil.isLoggable(LogUtil.BUGLE_TAG, LogUtil.VERBOSE)) { + LogUtil.v(LogUtil.BUGLE_TAG, this.getLocalClassName() + ".onStart"); + } + } + + @Override + protected void onRestart() { + super.onStop(); + if (LogUtil.isLoggable(LogUtil.BUGLE_TAG, LogUtil.VERBOSE)) { + LogUtil.v(LogUtil.BUGLE_TAG, this.getLocalClassName() + ".onRestart"); + } + } + + @Override + protected void onResume() { + super.onResume(); + if (LogUtil.isLoggable(LogUtil.BUGLE_TAG, LogUtil.VERBOSE)) { + LogUtil.v(LogUtil.BUGLE_TAG, this.getLocalClassName() + ".onResume"); + } + BugleActivityUtil.onActivityResume(this, BugleActionBarActivity.this); + } + + @Override + protected void onPause() { + super.onPause(); + if (LogUtil.isLoggable(LogUtil.BUGLE_TAG, LogUtil.VERBOSE)) { + LogUtil.v(LogUtil.BUGLE_TAG, this.getLocalClassName() + ".onPause"); + } + } + + @Override + protected void onStop() { + super.onStop(); + if (LogUtil.isLoggable(LogUtil.BUGLE_TAG, LogUtil.VERBOSE)) { + LogUtil.v(LogUtil.BUGLE_TAG, this.getLocalClassName() + ".onStop"); + } + } + + private boolean mDestroyed; + + @Override + protected void onDestroy() { + super.onDestroy(); + mDestroyed = true; + } + + public boolean getIsDestroyed() { + return mDestroyed; + } + + @Override + public void onDisplayHeightChanged(final int heightSpecification) { + int screenHeight = getResources().getDisplayMetrics().heightPixels; + + if (screenHeight != mLastScreenHeight) { + // Appears to be an orientation change, don't fire ime updates + mLastScreenHeight = screenHeight; + LogUtil.v(LogUtil.BUGLE_TAG, this.getLocalClassName() + ".onDisplayHeightChanged " + + " screenHeight: " + screenHeight + " lastScreenHeight: " + mLastScreenHeight + + " Skipped, appears to be orientation change."); + return; + } + final ActionBar actionBar = getSupportActionBar(); + if (actionBar != null && actionBar.isShowing()) { + screenHeight -= actionBar.getHeight(); + } + final int height = View.MeasureSpec.getSize(heightSpecification); + + final boolean imeWasOpen = mImeOpen; + mImeOpen = screenHeight - height > 100; + + if (LogUtil.isLoggable(LogUtil.BUGLE_TAG, LogUtil.VERBOSE)) { + LogUtil.v(LogUtil.BUGLE_TAG, this.getLocalClassName() + ".onDisplayHeightChanged " + + "imeWasOpen: " + imeWasOpen + " mImeOpen: " + mImeOpen + " screenHeight: " + + screenHeight + " height: " + height); + } + + if (imeWasOpen != mImeOpen) { + for (final ImeUtil.ImeStateObserver observer : mImeStateObservers) { + observer.onImeStateChanged(mImeOpen); + } + } + } + + @Override + public void registerImeStateObserver(final ImeUtil.ImeStateObserver observer) { + mImeStateObservers.add(observer); + } + + @Override + public void unregisterImeStateObserver(final ImeUtil.ImeStateObserver observer) { + mImeStateObservers.remove(observer); + } + + @Override + public boolean isImeOpen() { + return mImeOpen; + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + mActionBarMenu = menu; + if (mActionMode != null && + mActionMode.getCallback().onCreateActionMode(mActionMode, menu)) { + return true; + } + return false; + } + + @Override + public boolean onPrepareOptionsMenu(final Menu menu) { + mActionBarMenu = menu; + if (mActionMode != null && + mActionMode.getCallback().onPrepareActionMode(mActionMode, menu)) { + return true; + } + return super.onPrepareOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem menuItem) { + if (mActionMode != null && + mActionMode.getCallback().onActionItemClicked(mActionMode, menuItem)) { + return true; + } + + switch (menuItem.getItemId()) { + case android.R.id.home: + if (mActionMode != null) { + dismissActionMode(); + return true; + } + } + return super.onOptionsItemSelected(menuItem); + } + + @Override + public ActionMode startActionMode(final ActionMode.Callback callback) { + mActionMode = new CustomActionMode(callback); + supportInvalidateOptionsMenu(); + invalidateActionBar(); + return mActionMode; + } + + public void dismissActionMode() { + if (mActionMode != null) { + mActionMode.finish(); + mActionMode = null; + invalidateActionBar(); + } + } + + public ActionMode getActionMode() { + return mActionMode; + } + + protected ActionMode.Callback getActionModeCallback() { + if (mActionMode == null) { + return null; + } + + return mActionMode.getCallback(); + } + + /** + * Receives and handles action bar invalidation request from sub-components of this activity. + * + * <p>Normally actions have sole control over the action bar, but in order to support seamless + * transitions for components such as the full screen media picker, we have to let it take over + * the action bar and then restore its state afterwards</p> + * + * <p>If a fragment does anything that may change the action bar, it should call this method + * and then it is this method's responsibility to figure out which component "controls" the + * action bar and delegate the updating of the action bar to that component</p> + */ + public final void invalidateActionBar() { + if (mActionMode != null) { + mActionMode.updateActionBar(getSupportActionBar()); + } else { + updateActionBar(getSupportActionBar()); + } + } + + protected void updateActionBar(final ActionBar actionBar) { + actionBar.setHomeAsUpIndicator(null); + } + + /** + * Custom ActionMode implementation which allows us to just replace the contents of the main + * action bar rather than overlay over it + */ + private class CustomActionMode extends ActionMode { + private CharSequence mTitle; + private CharSequence mSubtitle; + private View mCustomView; + private final Callback mCallback; + + public CustomActionMode(final Callback callback) { + mCallback = callback; + } + + @Override + public void setTitle(final CharSequence title) { + mTitle = title; + } + + @Override + public void setTitle(final int resId) { + mTitle = getResources().getString(resId); + } + + @Override + public void setSubtitle(final CharSequence subtitle) { + mSubtitle = subtitle; + } + + @Override + public void setSubtitle(final int resId) { + mSubtitle = getResources().getString(resId); + } + + @Override + public void setCustomView(final View view) { + mCustomView = view; + } + + @Override + public void invalidate() { + invalidateActionBar(); + } + + @Override + public void finish() { + mActionMode = null; + mCallback.onDestroyActionMode(this); + supportInvalidateOptionsMenu(); + invalidateActionBar(); + } + + @Override + public Menu getMenu() { + return mActionBarMenu; + } + + @Override + public CharSequence getTitle() { + return mTitle; + } + + @Override + public CharSequence getSubtitle() { + return mSubtitle; + } + + @Override + public View getCustomView() { + return mCustomView; + } + + @Override + public MenuInflater getMenuInflater() { + return BugleActionBarActivity.this.getMenuInflater(); + } + + public Callback getCallback() { + return mCallback; + } + + public void updateActionBar(final ActionBar actionBar) { + actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP); + actionBar.setDisplayShowTitleEnabled(false); + actionBar.setDisplayShowCustomEnabled(false); + mActionMode.getCallback().onPrepareActionMode(mActionMode, mActionBarMenu); + actionBar.setBackgroundDrawable(new ColorDrawable( + getResources().getColor(R.color.contextual_action_bar_background_color))); + actionBar.setHomeAsUpIndicator(R.drawable.ic_cancel_small_dark); + actionBar.show(); + } + } +} |