Home | History | Annotate | Download | only in old
      1 /*
      2  * Copyright (C) 2014 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 com.android.tv.settings.dialog.old;
     18 
     19 import android.app.Activity;
     20 import android.app.Fragment;
     21 import android.app.FragmentManager;
     22 import android.app.FragmentManager.OnBackStackChangedListener;
     23 import android.app.FragmentTransaction;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.graphics.Color;
     27 import android.graphics.drawable.ColorDrawable;
     28 import android.net.Uri;
     29 import android.os.Build;
     30 import android.os.Bundle;
     31 import android.support.annotation.NonNull;
     32 import android.view.LayoutInflater;
     33 import android.view.View;
     34 import android.view.ViewGroup;
     35 import android.view.animation.Interpolator;
     36 
     37 import com.android.tv.settings.R;
     38 
     39 import java.util.ArrayList;
     40 
     41 /**
     42  * A DialogActivity has 2 fragments, a content fragment and a list fragment.
     43  * <p>
     44  * Subclasses should override to supply the content fragment and list items.
     45  * <p>
     46  * The DialogActivity will handle animating in and out.
     47  * <p>
     48  * This class will use a default layout, but a custom layout can be provided by
     49  * calling {@link #setLayoutProperties}
     50  */
     51 public abstract class DialogActivity extends Activity
     52         implements ActionAdapter.Listener, OnBackStackChangedListener {
     53 
     54     /**
     55      * Dialog Content Fragment title.
     56      */
     57     public static final String EXTRA_DIALOG_TITLE = "dialog_title";
     58 
     59     /**
     60      * Dialog Content Fragment breadcrumb.
     61      */
     62     public static final String EXTRA_DIALOG_BREADCRUMB = "dialog_breadcrumb";
     63 
     64     /**
     65      * Dialog Content Fragment description.
     66      */
     67     public static final String EXTRA_DIALOG_DESCRIPTION = "dialog_description";
     68 
     69     /**
     70      * Dialog Content Fragment image uri.
     71      */
     72     public static final String EXTRA_DIALOG_IMAGE_URI = "dialog_image_uri";
     73 
     74     /**
     75      * Dialog Content Fragment image background color
     76      */
     77     public static final String EXTRA_DIALOG_IMAGE_BACKGROUND_COLOR
     78             = "dialog_image_background_color";
     79 
     80     /**
     81      * Dialog Action Fragment actions starting index.
     82      */
     83     public static final String EXTRA_DIALOG_ACTIONS_START_INDEX = "dialog_actions_start_index";
     84 
     85     /**
     86      * Dialog Action Fragment actions.
     87      */
     88     public static final String EXTRA_PARCELABLE_ACTIONS = "parcelable_actions";
     89 
     90     /**
     91      * Whether DialogActivity should create Content Fragment and Action Fragment from extras.
     92      */
     93     public static final String EXTRA_CREATE_FRAGMENT_FROM_EXTRA = "create_fragment_from_extra";
     94 
     95     public static final String TAG_DIALOG = "tag_dialog";
     96     public static final String BACKSTACK_NAME_DIALOG = "backstack_name_dialog";
     97     public static final String KEY_BACKSTACK_COUNT = "backstack_count";
     98 
     99     protected static final int ANIMATE_IN_DURATION = 250;
    100 
    101     private DialogFragment mDialogFragment;
    102     private int mLayoutResId = R.layout.lb_dialog_fragment;
    103     private View mContent;
    104     private int mLastBackStackCount = 0;
    105 
    106     public DialogActivity() {
    107         mDialogFragment = new DialogFragment();
    108         mDialogFragment.setActivity(this);
    109     }
    110 
    111     public static Intent createIntent(Context context, String title,
    112             String breadcrumb, String description, String imageUri,
    113             ArrayList<Action> actions) {
    114         return createIntent(context, title, breadcrumb, description, imageUri,
    115                 Color.TRANSPARENT, actions);
    116     }
    117 
    118     public static Intent createIntent(Context context, String title,
    119             String breadcrumb, String description, String imageUri,
    120             int imageBackground, ArrayList<Action> actions) {
    121         Intent intent = new Intent(context, DialogActivity.class);
    122         intent.putExtra(EXTRA_DIALOG_TITLE, title);
    123         intent.putExtra(EXTRA_DIALOG_BREADCRUMB, breadcrumb);
    124         intent.putExtra(EXTRA_DIALOG_DESCRIPTION, description);
    125         intent.putExtra(EXTRA_DIALOG_IMAGE_URI, imageUri);
    126         intent.putExtra(EXTRA_DIALOG_IMAGE_BACKGROUND_COLOR, imageBackground);
    127         intent.putParcelableArrayListExtra(EXTRA_PARCELABLE_ACTIONS, actions);
    128 
    129         return intent;
    130     }
    131 
    132     public static Intent createIntent(Context context, String title,
    133             String breadcrumb, String description, String imageUri,
    134             ArrayList<Action> actions, Class<? extends DialogActivity> activityClass) {
    135         return createIntent(context, title, breadcrumb, description, imageUri, Color.TRANSPARENT,
    136                 actions, activityClass);
    137     }
    138 
    139     public static Intent createIntent(Context context, String title,
    140             String breadcrumb, String description, String imageUri, int imageBackground,
    141             ArrayList<Action> actions, Class<? extends DialogActivity> activityClass) {
    142         Intent intent = new Intent(context, activityClass);
    143         intent.putExtra(EXTRA_DIALOG_TITLE, title);
    144         intent.putExtra(EXTRA_DIALOG_BREADCRUMB, breadcrumb);
    145         intent.putExtra(EXTRA_DIALOG_DESCRIPTION, description);
    146         intent.putExtra(EXTRA_DIALOG_IMAGE_URI, imageUri);
    147         intent.putExtra(EXTRA_DIALOG_IMAGE_BACKGROUND_COLOR, imageBackground);
    148         intent.putParcelableArrayListExtra(EXTRA_PARCELABLE_ACTIONS, actions);
    149 
    150         return intent;
    151     }
    152 
    153     public static Intent createIntent(Context context, String title,
    154             String breadcrumb, String description, String imageUri, int imageBackground,
    155             ArrayList<Action> actions, Class<? extends DialogActivity> activityClass,
    156             int startIndex) {
    157         Intent intent = new Intent(context, activityClass);
    158         intent.putExtra(EXTRA_DIALOG_TITLE, title);
    159         intent.putExtra(EXTRA_DIALOG_BREADCRUMB, breadcrumb);
    160         intent.putExtra(EXTRA_DIALOG_DESCRIPTION, description);
    161         intent.putExtra(EXTRA_DIALOG_IMAGE_URI, imageUri);
    162         intent.putExtra(EXTRA_DIALOG_IMAGE_BACKGROUND_COLOR, imageBackground);
    163         intent.putParcelableArrayListExtra(EXTRA_PARCELABLE_ACTIONS, actions);
    164         intent.putExtra(EXTRA_DIALOG_ACTIONS_START_INDEX, startIndex);
    165 
    166         return intent;
    167     }
    168 
    169     public View getContentView() {
    170         return mContent;
    171     }
    172 
    173     @Override
    174     protected void onCreate(Bundle savedInstanceState) {
    175         // TODO: replace these hardcoded values with the commented constants whenever Hangouts
    176         // updates their manifest to build against JB MR2.
    177         if (Build.VERSION.SDK_INT >= 18 /* Build.VERSION_CODES.JELLY_BEAN_MR2 */) {
    178             getWindow().addFlags(0x02000000
    179                     /* WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN */);
    180         }
    181         if(savedInstanceState != null) {
    182             mLastBackStackCount = savedInstanceState.getInt(KEY_BACKSTACK_COUNT);
    183         }
    184 
    185         super.onCreate(savedInstanceState);
    186         getFragmentManager().addOnBackStackChangedListener(this);
    187 
    188         LayoutInflater helium = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    189         mContent = helium.inflate(mLayoutResId, null);
    190         setContentView(mContent);
    191         if (mLayoutResId == R.layout.lb_dialog_fragment) {
    192             helium.inflate(R.layout.dialog_container, (ViewGroup) mContent);
    193             setDialogFragment(mDialogFragment);
    194         }
    195 
    196         Bundle bundle = getIntent().getExtras();
    197         if (bundle != null) {
    198             boolean createFragmentFromExtra = bundle.getBoolean(EXTRA_CREATE_FRAGMENT_FROM_EXTRA);
    199             if (createFragmentFromExtra) {
    200                 // If intent bundle is not null, and flag indicates that should create fragments,
    201                 // set ContentFragment and ActionFragment using bundle extras.
    202                 String title = bundle.getString(EXTRA_DIALOG_TITLE);
    203                 String breadcrumb = bundle.getString(EXTRA_DIALOG_BREADCRUMB);
    204                 String description = bundle.getString(EXTRA_DIALOG_DESCRIPTION);
    205                 String imageUriStr = bundle.getString(EXTRA_DIALOG_IMAGE_URI);
    206                 Uri imageUri = Uri.parse(imageUriStr);
    207                 int backgroundColor = bundle.getInt(EXTRA_DIALOG_IMAGE_BACKGROUND_COLOR);
    208 
    209                 ArrayList<Action> actions =
    210                         bundle.getParcelableArrayList(EXTRA_PARCELABLE_ACTIONS);
    211 
    212                 setContentFragment(ContentFragment.newInstance(title, breadcrumb,
    213                         description, imageUri, backgroundColor));
    214 
    215                 setActionFragment(ActionFragment.newInstance(actions));
    216             }
    217         }
    218     }
    219 
    220     @Override
    221     protected void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
    222         super.onSaveInstanceState(savedInstanceState);
    223         savedInstanceState.putInt(KEY_BACKSTACK_COUNT, mLastBackStackCount);
    224     }
    225 
    226     @Override
    227     protected void onStart() {
    228         super.onStart();
    229         if (mLayoutResId == R.layout.lb_dialog_fragment) {
    230             getDialogFragment().performEntryTransition();
    231         }
    232     }
    233 
    234     @Override
    235     public void onBackStackChanged() {
    236         int count = getFragmentManager().getBackStackEntryCount();
    237         if (count > 0 && count < mLastBackStackCount && DialogActivity.BACKSTACK_NAME_DIALOG.equals(
    238                 getFragmentManager().getBackStackEntryAt(count - 1).getName())) {
    239             getFragmentManager().popBackStack();
    240         }
    241         mLastBackStackCount = count;
    242     }
    243 
    244     @Override
    245     public void onActionClicked(Action action) {
    246         Intent intent = action.getIntent();
    247         if (intent != null) {
    248             startActivity(intent);
    249             finish();
    250         }
    251     }
    252 
    253     /**
    254      * Disables the entry animation that normally happens onStart().
    255      */
    256     protected void disableEntryAnimation() {
    257         getDialogFragment().disableEntryAnimation();
    258     }
    259 
    260     /**
    261      * This method sets the layout property of this class. <br/>
    262      * Activities extending {@link DialogActivity} should call this method
    263      * before calling {@link #onCreate(Bundle)} if they want to have a
    264      * custom view.
    265      *
    266      * @param layoutResId resource if of the activity layout
    267      * @param contentAreaId id of the content area
    268      * @param actionAreaId id of the action area
    269      */
    270     protected void setLayoutProperties(int layoutResId, int contentAreaId, int actionAreaId) {
    271         mLayoutResId = layoutResId;
    272         getDialogFragment().setLayoutProperties(contentAreaId, actionAreaId);
    273     }
    274 
    275     /**
    276      * Animates a view.
    277      *
    278      * @param v              view to animate
    279      * @param initAlpha      initial alpha
    280      * @param initTransX     initial translation in the X
    281      * @param delay          delay in ms
    282      * @param duration       duration in ms
    283      * @param interpolator   interpolator to be used, can be null
    284      * @param isIcon         if {@code true}, this is the main icon being moved
    285      */
    286     protected void prepareAndAnimateView(final View v, float initAlpha, float initTransX, int delay,
    287             int duration, Interpolator interpolator, final boolean isIcon) {
    288         getDialogFragment().prepareAndAnimateView(
    289                 v, initAlpha, initTransX, delay, duration, interpolator, isIcon);
    290     }
    291 
    292     /**
    293      * Called when intro animation is finished.
    294      * <p>
    295      * If a subclass is going to alter the view, should wait until this is called.
    296      */
    297     protected void onIntroAnimationFinished() {
    298         getDialogFragment().onIntroAnimationFinished();
    299     }
    300 
    301     protected boolean isIntroAnimationInProgress() {
    302         return getDialogFragment().isIntroAnimationInProgress();
    303     }
    304 
    305     protected ColorDrawable getBackgroundDrawable() {
    306         return getDialogFragment().getBackgroundDrawable();
    307     }
    308 
    309     protected void setBackgroundDrawable(ColorDrawable drawable) {
    310         getDialogFragment().setBackgroundDrawable(drawable);
    311     }
    312 
    313     /**
    314      * Sets the content fragment into the view.
    315      */
    316     protected void setContentFragment(Fragment fragment) {
    317         getDialogFragment().setContentFragment(fragment);
    318     }
    319 
    320     /**
    321      * Sets the action fragment into the view.
    322      * <p>
    323      * If an action fragment currently exists, this will be added to the back stack.
    324      */
    325     protected void setActionFragment(Fragment fragment) {
    326         getDialogFragment().setActionFragment(fragment);
    327     }
    328 
    329     /**
    330      * Sets the action fragment into the view.
    331      * <p>
    332      * If addToBackStack is true, and action fragment currently exists,
    333      * this will be added to the back stack.
    334      */
    335     protected void setActionFragment(Fragment fragment, boolean addToBackStack) {
    336         getDialogFragment().setActionFragment(fragment, addToBackStack);
    337     }
    338 
    339     protected Fragment getActionFragment() {
    340         return getDialogFragment().getActionFragment();
    341     }
    342 
    343     protected Fragment getContentFragment() {
    344         return getDialogFragment().getContentFragment();
    345     }
    346 
    347     /**
    348      * Set the content and action fragments in the same transaction.
    349      * <p>
    350      * If an action fragment currently exists, this will be added to the back stack.
    351      */
    352     protected void setContentAndActionFragments(Fragment contentFragment, Fragment actionFragment) {
    353         getDialogFragment().setContentAndActionFragments(contentFragment, actionFragment);
    354     }
    355 
    356     /**
    357      * Set the content and action fragments in the same transaction.
    358      * <p>
    359      * If addToBackStack and an action fragment currently exists,
    360      * this will be added to the back stack.
    361      */
    362     protected void setContentAndActionFragments(Fragment contentFragment, Fragment actionFragment,
    363             boolean addToBackStack) {
    364         getDialogFragment().setContentAndActionFragments(
    365                 contentFragment, actionFragment, addToBackStack);
    366     }
    367 
    368     protected void setDialogFragment(DialogFragment fragment) {
    369         setDialogFragment(fragment, true);
    370     }
    371 
    372     protected void setDialogFragment(DialogFragment fragment, boolean addToBackStack) {
    373         mDialogFragment = fragment;
    374         fragment.setActivity(this);
    375         FragmentManager fm = getFragmentManager();
    376         FragmentTransaction ft = fm.beginTransaction();
    377         boolean hasDialog = fm.findFragmentByTag(DialogActivity.TAG_DIALOG) != null;
    378         if (hasDialog) {
    379             if (addToBackStack) {
    380                 ft.addToBackStack(DialogActivity.BACKSTACK_NAME_DIALOG);
    381             }
    382         }
    383         ft.replace(R.id.dialog_fragment, fragment, DialogActivity.TAG_DIALOG);
    384         ft.commit();
    385     }
    386 
    387     protected DialogFragment getDialogFragment() {
    388         final DialogFragment fragment =
    389                 (DialogFragment) getFragmentManager().findFragmentByTag(TAG_DIALOG);
    390         if (fragment != null) {
    391             mDialogFragment = fragment;
    392         }
    393 
    394         return mDialogFragment;
    395     }
    396 }
    397