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