Home | History | Annotate | Download | only in menu
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.support.car.app.menu;
     18 
     19 import android.content.Context;
     20 import android.graphics.Bitmap;
     21 import android.graphics.drawable.Drawable;
     22 import android.os.Bundle;
     23 import android.os.Handler;
     24 import android.support.annotation.LayoutRes;
     25 import android.support.car.Car;
     26 import android.support.car.app.CarFragmentActivity;
     27 import android.support.car.app.menu.compat.CarMenuConstantsComapt.MenuItemConstants;
     28 import android.support.car.input.CarInputManager;
     29 import android.support.v4.app.Fragment;
     30 import android.util.DisplayMetrics;
     31 import android.view.LayoutInflater;
     32 import android.view.View;
     33 import android.view.ViewGroup;
     34 import android.view.WindowManager;
     35 import android.widget.EditText;
     36 
     37 /**
     38  * Base class for a car app which wants to use a drawer.
     39  */
     40 public abstract class CarDrawerActivity extends CarFragmentActivity {
     41     private static final String TAG = "CarDrawerActivity";
     42 
     43     private static final String KEY_DRAWERSHOWING =
     44             "android.support.car.app.CarDrawerActivity.DRAWER_SHOWING";
     45     private static final String KEY_INPUTSHOWING =
     46             "android.support.car.app.CarDrawerActivity.INPUT_SHOWING";
     47     private static final String KEY_SEARCHBOXENABLED =
     48             "android.support.car.app.CarDrawerActivity.SEARCH_BOX_ENABLED";
     49 
     50     private final Handler mHandler = new Handler();
     51     private final CarUiController mUiController;
     52 
     53     private CarMenuCallbacks mMenuCallbacks;
     54     private OnMenuClickListener mMenuClickListener;
     55     private boolean mDrawerShowing;
     56     private boolean mShowingSearchBox;
     57     private boolean mSearchBoxEnabled;
     58     private boolean mOnCreateCalled = false;
     59     private View.OnClickListener mSearchBoxOnClickListener;
     60 
     61     private CarInputManager mInputManager;
     62     private EditText mSearchBoxView;
     63 
     64     public interface OnMenuClickListener {
     65         /**
     66          * Called when the menu button is clicked.
     67          *
     68          * @return True if event was handled. This will prevent the drawer from executing its
     69          *         default action (opening/closing/going back). False if the event was not handled
     70          *         so the drawer will execute the default action.
     71          */
     72         boolean onClicked();
     73     }
     74 
     75     public CarDrawerActivity(Proxy proxy, Context context, Car car) {
     76         super(proxy, context, car);
     77         mUiController = createCarUiController();
     78     }
     79 
     80     /**
     81      * Create a {@link android.support.car.app.menu.CarUiController}.
     82      *
     83      * Derived class can override this function to return a customized ui controller.
     84      */
     85     protected CarUiController createCarUiController() {
     86         return CarUiController.createCarUiController(this);
     87     }
     88 
     89     @Override
     90     public void setContentView(View view) {
     91         ViewGroup parent = (ViewGroup) findViewById(mUiController.getFragmentContainerId());
     92         parent.addView(view);
     93     }
     94 
     95     @Override
     96     public void setContentView(@LayoutRes int resourceId) {
     97         ViewGroup parent = (ViewGroup) findViewById(mUiController.getFragmentContainerId());
     98         LayoutInflater inflater = getLayoutInflater();
     99         inflater.inflate(resourceId, parent, true);
    100     }
    101 
    102     @Override
    103     public View findViewById(@LayoutRes int id) {
    104         return super.findViewById(mUiController.getFragmentContainerId()).findViewById(id);
    105     }
    106 
    107     @Override
    108     protected void onCreate(Bundle savedInstanceState) {
    109         super.onCreate(savedInstanceState);
    110         super.setContentView(mUiController.getContentView());
    111         mInputManager = getInputManager();
    112         mHandler.post(new Runnable() {
    113             @Override
    114             public void run() {
    115                 if (mMenuCallbacks != null) {
    116                     mMenuCallbacks.registerOnChildrenChangedListener(mMenuListener);
    117                 }
    118                 mOnCreateCalled = true;
    119             }
    120         });
    121     }
    122 
    123     @Override
    124     protected void onDestroy() {
    125         super.onDestroy();
    126         mHandler.post(new Runnable() {
    127             @Override
    128             public void run() {
    129                 if (mMenuCallbacks != null) {
    130                     mMenuCallbacks.unregisterOnChildrenChangedListener(mMenuListener);
    131                     mMenuCallbacks = null;
    132                 }
    133             }
    134         });
    135     }
    136 
    137     @Override
    138     protected void onRestoreInstanceState(Bundle savedInstanceState) {
    139         super.onRestoreInstanceState(savedInstanceState);
    140         mDrawerShowing = savedInstanceState.getBoolean(KEY_DRAWERSHOWING);
    141         mUiController.onRestoreInstanceState(savedInstanceState);
    142     }
    143 
    144     @Override
    145     protected void onSaveInstanceState(Bundle outState) {
    146         super.onSaveInstanceState(outState);
    147         outState.putBoolean(KEY_DRAWERSHOWING, mDrawerShowing);
    148         mUiController.onSaveInstanceState(outState);
    149     }
    150 
    151     @Override
    152     protected void onStart() {
    153         super.onStart();
    154         getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
    155         mUiController.onStart();
    156     }
    157 
    158     @Override
    159     protected void onResume() {
    160         super.onResume();
    161         mUiController.onResume();
    162     }
    163 
    164     @Override
    165     protected void onPause() {
    166         super.onPause();
    167         mUiController.onPause();
    168     }
    169 
    170     @Override
    171     protected void onStop() {
    172         super.onStop();
    173         mUiController.onStop();
    174     }
    175 
    176     /**
    177      * Set the fragment in the main fragment container.
    178      */
    179     public void setContentFragment(Fragment fragment) {
    180         super.setContentFragment(fragment, mUiController.getFragmentContainerId());
    181     }
    182 
    183     /**
    184      * Return the main fragment container id for the app.
    185      */
    186     public int getFragmentContainerId() {
    187         return mUiController.getFragmentContainerId();
    188     }
    189 
    190     /**
    191      * Set the callbacks for car menu interactions.
    192      */
    193     public void setCarMenuCallbacks(final CarMenuCallbacks callbacks) {
    194         if (mOnCreateCalled) {
    195             throw new IllegalStateException(
    196                     "Cannot call setCarMenuCallbacks after onCreate has been called.");
    197         }
    198         mMenuCallbacks = callbacks;
    199         mUiController.registerCarMenuCallbacks(callbacks);
    200     }
    201 
    202     /**
    203      * Listener that listens for when the menu button is pressed.
    204      *
    205      * @param listener {@link OnMenuClickListener} that will listen for menu button clicks.
    206      */
    207     public void setOnMenuClickedListener(OnMenuClickListener listener) {
    208         mMenuClickListener = listener;
    209     }
    210 
    211     /**
    212      * Restore the menu button drawable
    213      */
    214     public void restoreMenuButtonDrawable() {
    215         mUiController.restoreMenuButtonDrawable();
    216     }
    217 
    218     /**
    219      * Sets the menu button bitmap
    220      *
    221      * @param bitmap Bitmap to the menu button to.
    222      */
    223     public void setMenuButtonBitmap(Bitmap bitmap) {
    224         mUiController.setMenuButtonBitmap(bitmap);
    225     }
    226 
    227     /**
    228      * Set the title of the menu.
    229      */
    230     public void setTitle(CharSequence title) {
    231         mUiController.setTitle(title);
    232     }
    233 
    234     /**
    235      * Set the System UI to be light.
    236      */
    237     public void setLightMode() {
    238         mUiController.setLightMode();
    239     }
    240 
    241     /**
    242      * Set the System UI to be dark.
    243      */
    244     public void setDarkMode() {
    245         mUiController.setDarkMode();
    246     }
    247 
    248     /**
    249      * Set the System UI to be dark during day mode and light during night mode.
    250      */
    251     public void setAutoLightDarkMode() {
    252         mUiController.setAutoLightDarkMode();
    253     }
    254 
    255     /**
    256      * Sets the application background to the given {@link android.graphics.Bitmap}.
    257      *
    258      * @param bitmap to use as background.
    259      */
    260     public void setBackground(Bitmap bitmap) {
    261         mUiController.setBackground(bitmap);
    262     }
    263 
    264     /**
    265      * Sets the color of the scrim to the right of the car menu drawer.
    266      */
    267     public void setScrimColor(int color) {
    268         mUiController.setScrimColor(color);
    269     }
    270 
    271     /**
    272      * Show the menu associated with the given id in the drawer.
    273      *
    274      * @param id Id of the menu to link to.
    275      * @param title Title that should be displayed.
    276      */
    277     public void showMenu(String id, String title) {
    278         mUiController.showMenu(id, title);
    279     }
    280 
    281     public boolean onMenuClicked() {
    282         if (mMenuClickListener != null) {
    283             return mMenuClickListener.onClicked();
    284         }
    285         return false;
    286     }
    287 
    288     public void restoreSearchBox() {
    289         if (isSearchBoxEnabled()) {
    290             mUiController.showSearchBox(mSearchBoxOnClickListener);
    291             mShowingSearchBox = true;
    292         }
    293     }
    294 
    295     private final CarMenuCallbacks.OnChildrenChangedListener mMenuListener =
    296             new CarMenuCallbacks.OnChildrenChangedListener() {
    297                 @Override
    298                 public void onChildrenChanged(String parentId) {
    299                     if (mOnCreateCalled) {
    300                         mUiController.onChildrenChanged(parentId);
    301                     }
    302                 }
    303 
    304                 @Override
    305                 public void onChildChanged(String parentId, Bundle item,
    306                         Drawable leftIcon, Drawable rightIcon) {
    307                     DisplayMetrics metrics = getResources().getDisplayMetrics();
    308                     if (leftIcon != null) {
    309                         item.putParcelable(MenuItemConstants.KEY_LEFTICON,
    310                                 Utils.snapshot(metrics, leftIcon));
    311                     }
    312 
    313                     if (rightIcon != null) {
    314                         item.putParcelable(MenuItemConstants.KEY_RIGHTICON,
    315                                 Utils.snapshot(metrics, rightIcon));
    316                     }
    317                     if (mOnCreateCalled) {
    318                         mUiController.onChildChanged(parentId, item);
    319                     }
    320                 }
    321             };
    322 
    323     public void closeDrawer() {
    324         mUiController.closeDrawer();
    325     }
    326 
    327     public void openDrawer() {
    328         mUiController.openDrawer();
    329     }
    330 
    331     public boolean isDrawerShowing() {
    332         return mDrawerShowing;
    333     }
    334 
    335     public void setDrawerShowing(boolean showing) {
    336         mDrawerShowing = showing;
    337     }
    338 
    339     public boolean isSearchBoxEnabled() {
    340         return mSearchBoxEnabled;
    341     }
    342 
    343     public boolean isShowingSearchBox() {
    344         return mShowingSearchBox;
    345     }
    346 
    347     /**
    348      * Shows a small clickable {@link android.widget.EditText}.
    349      *
    350      * {@link View} will be {@code null} in {@link View.OnClickListener#onClick(View)}.
    351      *
    352      * @param listener {@link View.OnClickListener} that is called when user selects the
    353      *                 {@link android.widget.EditText}.
    354      */
    355     public void showSearchBox(View.OnClickListener listener) {
    356         if (!isDrawerShowing()) {
    357             mUiController.showSearchBox(listener);
    358             mShowingSearchBox = true;
    359         }
    360         mSearchBoxEnabled = true;
    361         mSearchBoxOnClickListener = listener;
    362     }
    363 
    364     public void showSearchBox() {
    365         showSearchBox(mSearchBoxOnClickListener);
    366     }
    367 
    368     public void hideSearchBox() {
    369         if (isShowingSearchBox()) {
    370             stopInput();
    371         }
    372         mSearchBoxEnabled = false;
    373     }
    374 
    375     public void setSearchBoxEditListener(SearchBoxEditListener listener) {
    376         mUiController.setSearchBoxEditListener(listener);
    377     }
    378 
    379     public void stopInput() {
    380         // STOPSHIP: sometimes focus is lost and we are not able to hide the keyboard.
    381         // properly fix this before we ship.
    382         if (mSearchBoxView != null) {
    383             mSearchBoxView.requestFocusFromTouch();
    384         }
    385         mUiController.stopInput();
    386         mInputManager.stopInput();
    387         mShowingSearchBox = false;
    388     }
    389 
    390     /**
    391      * Start input on the search box that is provided by a car ui provider.
    392      * TODO: Migrate to use the new input/search api once it becomes stable (b/27108311).
    393      * @param hint Search hint
    394      */
    395     public void startInput(String hint) {
    396         startInput(hint, mSearchBoxOnClickListener);
    397     }
    398 
    399     /**
    400      * Start input on the search box that is provided by a car ui provider.
    401      * TODO: Migrate to use the new input/search api once it becomes stable (b/27108311).
    402      * @param hint Search hint
    403      * @param onClickListener Listener for the search box clicks.
    404      */
    405     public void startInput(final String hint, final View.OnClickListener onClickListener) {
    406         mInputManager = getInputManager();
    407         EditText inputView = mUiController.startInput(hint, onClickListener);
    408         getInputManager().startInput(inputView);
    409         mSearchBoxView = inputView;
    410         mShowingSearchBox = true;
    411     }
    412 
    413     public void setSearchBoxColors(int backgroundColor, int searchLogoColor, int textColor,
    414             int hintTextColor) {
    415         mUiController.setSearchBoxColors(backgroundColor, searchLogoColor,
    416                 textColor, hintTextColor);
    417     }
    418 
    419     public void setSearchBoxEndView(View endView) {
    420         mUiController.setSearchBoxEndView(endView);
    421     }
    422 
    423     public void showToast(String text, int duration) {
    424         mUiController.showToast(text, duration);
    425     }
    426 }
    427