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.FragmentTransaction;
23 import android.graphics.drawable.ColorDrawable;
24 import android.os.Bundle;
25 import android.view.View;
26 import android.view.ViewGroup;
27 import android.view.animation.Interpolator;
28 
29 import com.android.tv.settings.R;
30 
31 /**
32 * A DialogFragment has 2 fragments, a content fragment and a list fragment.
33 * <p>
34 * Subclasses should override to supply the content fragment and list items.
35 * <p>
36 * The DialogFragment will handle animating in and out.
37 * <p>
38 * This class will use a default layout, but a custom layout can be provided by
39 * calling {@link #setLayoutProperties}
40 */
41 public class DialogFragment extends Fragment implements ActionAdapter.Listener, LiteFragment {
42 
43     private Activity mActivity;
44     private final BaseDialogFragment mBase = new BaseDialogFragment(this);
45 
46     @Override
onActionClicked(Action action)47     public void onActionClicked(Action action) {
48         mBase.onActionClicked(getRealActivity(), action);
49     }
50 
disableEntryAnimation()51     protected void disableEntryAnimation() {
52         mBase.disableEntryAnimation();
53     }
54 
performEntryTransition()55     public void performEntryTransition() {
56         if (mBase.mFirstOnStart) {
57             mBase.mFirstOnStart = false;
58             // Once the subclass has setup its view hierarchy, we can perform an entry
59             // transition if specified by the intent.
60             Fragment fragment = getContentFragment();
61             if (fragment instanceof ContentFragment) {
62                 ContentFragment cf = (ContentFragment) fragment;
63                 mBase.performEntryTransition(getRealActivity(),
64                         (ViewGroup) getRealActivity().findViewById(android.R.id.content),
65                         cf.getIconResourceId(), cf.getIconResourceUri(),
66                         cf.getIcon(), cf.getTitle(), cf.getDescription(), cf.getBreadCrumb());
67             }
68         }
69     }
70 
71     /**
72      * This method sets the layout property of this class. <br/>
73      * Activities extending {@link DialogFragment} should call this method
74      * before calling {@link #onCreate(Bundle)} if they want to have a
75      * custom view.
76      *
77      * @param contentAreaId id of the content area
78      * @param actionAreaId id of the action area
79      */
setLayoutProperties(int contentAreaId, int actionAreaId)80     protected void setLayoutProperties(int contentAreaId, int actionAreaId) {
81         mBase.setLayoutProperties(contentAreaId, actionAreaId);
82     }
83 
84     /**
85      * Animates a view.
86      *
87      * @param v              view to animate
88      * @param initAlpha      initial alpha
89      * @param initTransX     initial translation in the X
90      * @param delay          delay in ms
91      * @param duration       duration in ms
92      * @param interpolator   interpolator to be used, can be null
93      * @param isIcon         if {@code true}, this is the main icon being moved
94      */
prepareAndAnimateView(final View v, float initAlpha, float initTransX, int delay, int duration, Interpolator interpolator, final boolean isIcon)95     protected void prepareAndAnimateView(final View v, float initAlpha, float initTransX, int delay,
96             int duration, Interpolator interpolator, final boolean isIcon) {
97         mBase.prepareAndAnimateView(
98                 v, initAlpha, initTransX, delay, duration, interpolator, isIcon);
99     }
100 
101     /**
102      * Called when intro animation is finished.
103      * <p>
104      * If a subclass is going to alter the view, should wait until this is called.
105      */
onIntroAnimationFinished()106     protected void onIntroAnimationFinished() {
107         mBase.onIntroAnimationFinished();
108     }
109 
isIntroAnimationInProgress()110     protected boolean isIntroAnimationInProgress() {
111         return mBase.isIntroAnimationInProgress();
112     }
113 
getBackgroundDrawable()114     protected ColorDrawable getBackgroundDrawable() {
115         return mBase.getBackgroundDrawable();
116     }
117 
setBackgroundDrawable(ColorDrawable drawable)118     protected void setBackgroundDrawable(ColorDrawable drawable) {
119         mBase.setBackgroundDrawable(drawable);
120     }
121 
122     /* ********************************************************************* */
123     /* Fragment related code below, cannot be placed into BaseDialogFragment */
124     /* ********************************************************************* */
125 
setActivity(Activity act)126     public void setActivity(Activity act) {
127         mActivity = act;
128     }
129 
130     /**
131      * Capable of returning {@link Activity} prior to this Fragment being
132      * attached to it's parent Activity.  Useful for getting the parent
133      * Activity prior to {@link #onAttach(Activity)} being called.
134      * @return parent {@link Activity}
135      */
getRealActivity()136     private Activity getRealActivity() {
137         return (mActivity != null ? mActivity : getActivity());
138     }
139 
140     /**
141      * Sets the content fragment into the view.
142      */
setContentFragment(Fragment fragment)143     protected void setContentFragment(Fragment fragment) {
144         FragmentTransaction ft = getContentFragmentTransaction(fragment);
145         ft.commit();
146     }
147 
148     /**
149      * Sets the action fragment into the view.
150      * <p>
151      * If an action fragment currently exists, this will be added to the back stack.
152      */
setActionFragment(Fragment fragment)153     protected void setActionFragment(Fragment fragment) {
154         setActionFragment(fragment, true);
155     }
156 
157     /**
158      * Sets the action fragment into the view.
159      * <p>
160      * If addToBackStack is true, and action fragment currently exists,
161      * this will be added to the back stack.
162      */
setActionFragment(Fragment fragment, boolean addToBackStack)163     protected void setActionFragment(Fragment fragment, boolean addToBackStack) {
164         FragmentTransaction ft = addActionFragmentToTransaction(fragment, null, addToBackStack,
165                 getRealActivity().getFragmentManager());
166         ft.commit();
167     }
168 
getActionFragment()169     protected Fragment getActionFragment() {
170         return getRealActivity().getFragmentManager()
171                 .findFragmentByTag(BaseDialogFragment.TAG_ACTION);
172     }
173 
getContentFragment()174     protected Fragment getContentFragment() {
175         return getRealActivity().getFragmentManager()
176                 .findFragmentByTag(BaseDialogFragment.TAG_CONTENT);
177     }
178 
179     /**
180      * Set the content and action fragments in the same transaction.
181      * <p>
182      * If an action fragment currently exists, this will be added to the back stack.
183      */
setContentAndActionFragments(Fragment contentFragment, Fragment actionFragment)184     protected void setContentAndActionFragments(Fragment contentFragment, Fragment actionFragment) {
185         setContentAndActionFragments(contentFragment, actionFragment, true);
186     }
187 
188     /**
189      * Set the content and action fragments in the same transaction.
190      * <p>
191      * If addToBackStack and an action fragment currently exists,
192      * this will be added to the back stack.
193      */
setContentAndActionFragments(Fragment contentFragment, Fragment actionFragment, boolean addToBackStack)194     protected void setContentAndActionFragments(Fragment contentFragment, Fragment actionFragment,
195             boolean addToBackStack) {
196         FragmentTransaction ft = getContentFragmentTransaction(contentFragment);
197         ft = addActionFragmentToTransaction(actionFragment, ft, addToBackStack,
198                 getRealActivity().getFragmentManager());
199         ft.commit();
200     }
201 
202     /**
203      * Begins a fragment transaction to edit the content fragment.
204      */
getContentFragmentTransaction(Fragment fragment)205     private FragmentTransaction getContentFragmentTransaction(Fragment fragment) {
206         FragmentManager fm = getRealActivity().getFragmentManager();
207         boolean hasContent = fm.findFragmentByTag(BaseDialogFragment.TAG_CONTENT) != null;
208         FragmentTransaction ft = fm.beginTransaction();
209 
210         if (hasContent) {
211             addAnimations(ft);
212         }
213         ft.replace(mBase.mContentAreaId, fragment, BaseDialogFragment.TAG_CONTENT);
214         return ft;
215     }
216 
217     /**
218      * Adds an action fragment replacement to an existing fragment transaction, or creates one if
219      * necessary.
220      * <p>
221      * If an action fragment currently exists, this will be added to the back stack.
222      */
addActionFragmentToTransaction(Fragment fragment, FragmentTransaction ft, boolean addToBackStack, FragmentManager fm)223     private FragmentTransaction addActionFragmentToTransaction(Fragment fragment,
224             FragmentTransaction ft, boolean addToBackStack, FragmentManager fm) {
225         if (ft == null) {
226             ft = fm.beginTransaction();
227         }
228         boolean hasActions = fm.findFragmentByTag(BaseDialogFragment.TAG_ACTION) != null;
229         if (hasActions) {
230             addAnimations(ft);
231             if (addToBackStack) {
232                 ft.addToBackStack(null);
233             }
234         }
235         ft.replace(mBase.mActionAreaId, fragment, BaseDialogFragment.TAG_ACTION);
236 
237         if (fragment instanceof ActionFragment) {
238             if (!((ActionFragment) fragment).hasListener()) {
239                 ((ActionFragment) fragment).setListener(this);
240             }
241         }
242 
243         return ft;
244     }
245 
addAnimations(FragmentTransaction ft)246     static void addAnimations(FragmentTransaction ft) {
247         ft.setCustomAnimations(R.anim.fragment_slide_left_in,
248                 R.anim.fragment_slide_left_out, R.anim.fragment_slide_right_in,
249                 R.anim.fragment_slide_right_out);
250     }
251 }
252 
253