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