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 android.support.v4.app.FragmentActivity;
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    * @return The parent of frag that implements the callbackInterface or null if no such parent can
38    *     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 {
55       FragmentActivity activity = fragment.getActivity();
56       if (callbackInterface.isInstance(activity)) {
57         @SuppressWarnings("unchecked") // Casts are checked using runtime methods
58         T parent = (T) activity;
59         return parent;
60       }
61     }
62     return null;
63   }
64 
65   /** Returns the parent or throws. Should perform check elsewhere(e.g. onAttach, newInstance). */
66   @NonNull
getParentUnsafe( @onNull Fragment fragment, @NonNull Class<T> callbackInterface)67   public static <T> T getParentUnsafe(
68       @NonNull Fragment fragment, @NonNull Class<T> callbackInterface) {
69     return Assert.isNotNull(getParent(fragment, callbackInterface));
70   }
71 
72   /**
73    * Ensures fragment has a parent that implements the corresponding interface
74    *
75    * @param frag The Fragment whose parents are to be checked
76    * @param callbackInterface The interface class that a parent should implement
77    * @throws IllegalStateException if no parents are found that implement callbackInterface
78    */
checkParent(@onNull Fragment frag, @NonNull Class<?> callbackInterface)79   public static void checkParent(@NonNull Fragment frag, @NonNull Class<?> callbackInterface)
80       throws IllegalStateException {
81     if (parentForTesting != null) {
82       return;
83     }
84     if (FragmentUtils.getParent(frag, callbackInterface) == null) {
85       String parent =
86           frag.getParentFragment() == null
87               ? frag.getActivity().getClass().getName()
88               : frag.getParentFragment().getClass().getName();
89       throw new IllegalStateException(
90           frag.getClass().getName()
91               + " must be added to a parent"
92               + " that implements "
93               + callbackInterface.getName()
94               + ". Instead found "
95               + parent);
96     }
97   }
98 }
99