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