• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.dialer.common;
18 
19 import android.support.annotation.CheckResult;
20 import android.support.annotation.NonNull;
21 import android.support.annotation.Nullable;
22 import android.support.annotation.VisibleForTesting;
23 import android.support.v4.app.Fragment;
24 import com.android.dialer.main.MainActivityPeer;
25 
26 /** Utility methods for working with Fragments */
27 public class FragmentUtils {
28 
29   private static Object parentForTesting;
30 
31   @VisibleForTesting(otherwise = VisibleForTesting.NONE)
setParentForTesting(Object parentForTesting)32   public static void setParentForTesting(Object parentForTesting) {
33     FragmentUtils.parentForTesting = parentForTesting;
34   }
35 
36   /**
37    * Returns an instance of the {@code callbackInterface} that is defined in the parent of the
38    * {@code fragment}, or null if no such call back can be found.
39    */
40   @CheckResult(suggest = "#checkParent(Fragment, Class)}")
41   @Nullable
getParent(@onNull Fragment fragment, @NonNull Class<T> callbackInterface)42   public static <T> T getParent(@NonNull Fragment fragment, @NonNull Class<T> callbackInterface) {
43     if (callbackInterface.isInstance(parentForTesting)) {
44       @SuppressWarnings("unchecked") // Casts are checked using runtime methods
45       T parent = (T) parentForTesting;
46       return parent;
47     }
48 
49     Fragment parentFragment = fragment.getParentFragment();
50     if (callbackInterface.isInstance(parentFragment)) {
51       @SuppressWarnings("unchecked") // Casts are checked using runtime methods
52       T parent = (T) parentFragment;
53       return parent;
54     } else if (callbackInterface.isInstance(fragment.getActivity())) {
55       @SuppressWarnings("unchecked") // Casts are checked using runtime methods
56       T parent = (T) fragment.getActivity();
57       return parent;
58     } else if (fragment.getActivity() instanceof FragmentUtilListener) {
59       @SuppressWarnings("unchecked") // Casts are checked using runtime methods
60       T parent = ((FragmentUtilListener) fragment.getActivity()).getImpl(callbackInterface);
61       return parent;
62     }
63     return null;
64   }
65 
66   /**
67    * Returns an instance of the {@code callbackInterface} that is defined in the parent of the
68    * {@code fragment}, or null if no such call back can be found.
69    */
70   @CheckResult(suggest = "#checkParent(Fragment, Class)}")
71   @Nullable
getParent( @onNull android.app.Fragment fragment, @NonNull Class<T> callbackInterface)72   public static <T> T getParent(
73       @NonNull android.app.Fragment fragment, @NonNull Class<T> callbackInterface) {
74     if (callbackInterface.isInstance(parentForTesting)) {
75       @SuppressWarnings("unchecked") // Casts are checked using runtime methods
76       T parent = (T) parentForTesting;
77       return parent;
78     }
79 
80     android.app.Fragment parentFragment = fragment.getParentFragment();
81     if (callbackInterface.isInstance(parentFragment)) {
82       @SuppressWarnings("unchecked") // Casts are checked using runtime methods
83       T parent = (T) parentFragment;
84       return parent;
85     } else if (callbackInterface.isInstance(fragment.getActivity())) {
86       @SuppressWarnings("unchecked") // Casts are checked using runtime methods
87       T parent = (T) fragment.getActivity();
88       return parent;
89     } else if (fragment.getActivity() instanceof FragmentUtilListener) {
90       @SuppressWarnings("unchecked") // Casts are checked using runtime methods
91       T parent = ((FragmentUtilListener) fragment.getActivity()).getImpl(callbackInterface);
92       return parent;
93     } else if (fragment.getActivity() instanceof MainActivityPeer.PeerSupplier) {
94       MainActivityPeer peer = ((MainActivityPeer.PeerSupplier) fragment.getActivity()).getPeer();
95       if (peer instanceof FragmentUtilListener) {
96         return ((FragmentUtilListener) peer).getImpl(callbackInterface);
97       }
98     }
99     return null;
100   }
101 
102   /** Returns the parent or throws. Should perform check elsewhere(e.g. onAttach, newInstance). */
103   @NonNull
getParentUnsafe( @onNull Fragment fragment, @NonNull Class<T> callbackInterface)104   public static <T> T getParentUnsafe(
105       @NonNull Fragment fragment, @NonNull Class<T> callbackInterface) {
106     return Assert.isNotNull(getParent(fragment, callbackInterface));
107   }
108 
109   /**
110    * Version of {@link #getParentUnsafe(Fragment, Class)} which supports {@link
111    * android.app.Fragment}.
112    */
113   @NonNull
getParentUnsafe( @onNull android.app.Fragment fragment, @NonNull Class<T> callbackInterface)114   public static <T> T getParentUnsafe(
115       @NonNull android.app.Fragment fragment, @NonNull Class<T> callbackInterface) {
116     return Assert.isNotNull(getParent(fragment, callbackInterface));
117   }
118 
119   /**
120    * Ensures fragment has a parent that implements the corresponding interface
121    *
122    * @param frag The Fragment whose parents are to be checked
123    * @param callbackInterface The interface class that a parent should implement
124    * @throws IllegalStateException if no parents are found that implement callbackInterface
125    */
checkParent(@onNull Fragment frag, @NonNull Class<?> callbackInterface)126   public static void checkParent(@NonNull Fragment frag, @NonNull Class<?> callbackInterface)
127       throws IllegalStateException {
128     if (parentForTesting != null) {
129       return;
130     }
131     if (FragmentUtils.getParent(frag, callbackInterface) == null) {
132       String parent =
133           frag.getParentFragment() == null
134               ? frag.getActivity().getClass().getName()
135               : frag.getParentFragment().getClass().getName();
136       throw new IllegalStateException(
137           frag.getClass().getName()
138               + " must be added to a parent"
139               + " that implements "
140               + callbackInterface.getName()
141               + ". Instead found "
142               + parent);
143     }
144   }
145 
146   /** Useful interface for activities that don't want to implement arbitrary listeners. */
147   public interface FragmentUtilListener {
148 
149     /** Returns an implementation of T if parent has one, otherwise null. */
150     @Nullable
getImpl(Class<T> callbackInterface)151     <T> T getImpl(Class<T> callbackInterface);
152   }
153 }
154