1 /* 2 * Copyright (C) 2018 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.google.android.setupcompat.internal; 18 19 import static java.util.concurrent.TimeUnit.NANOSECONDS; 20 21 import android.app.Activity; 22 import android.app.Fragment; 23 import android.app.FragmentManager; 24 import android.content.Context; 25 import android.os.Build.VERSION; 26 import android.os.Build.VERSION_CODES; 27 import android.util.Log; 28 import com.google.android.setupcompat.logging.MetricKey; 29 import com.google.android.setupcompat.logging.SetupMetricsLogger; 30 import com.google.android.setupcompat.util.WizardManagerHelper; 31 32 /** Fragment used to detect lifecycle of an activity for metrics logging. */ 33 public class LifecycleFragment extends Fragment { 34 private static final String LOG_TAG = LifecycleFragment.class.getSimpleName(); 35 private static final String FRAGMENT_ID = "lifecycle_monitor"; 36 37 private MetricKey metricKey; 38 private long startInNanos; 39 private long durationInNanos = 0; 40 41 public LifecycleFragment() { 42 setRetainInstance(true); 43 } 44 45 /** 46 * Attaches the lifecycle fragment if it is not attached yet. 47 * 48 * @param activity the activity to detect lifecycle for. 49 * @return fragment to monitor life cycle. 50 */ 51 public static LifecycleFragment attachNow(Activity activity) { 52 if (WizardManagerHelper.isAnySetupWizard(activity.getIntent())) { 53 SetupCompatServiceInvoker.get(activity.getApplicationContext()) 54 .bindBack( 55 LayoutBindBackHelper.getScreenName(activity), 56 LayoutBindBackHelper.getExtraBundle(activity)); 57 58 if (VERSION.SDK_INT > VERSION_CODES.M) { 59 FragmentManager fragmentManager = activity.getFragmentManager(); 60 if (fragmentManager != null && !fragmentManager.isDestroyed()) { 61 Fragment fragment = fragmentManager.findFragmentByTag(FRAGMENT_ID); 62 if (fragment == null) { 63 LifecycleFragment lifeCycleFragment = new LifecycleFragment(); 64 try { 65 fragmentManager.beginTransaction().add(lifeCycleFragment, FRAGMENT_ID).commitNow(); 66 fragment = lifeCycleFragment; 67 } catch (IllegalStateException e) { 68 Log.e( 69 LOG_TAG, 70 "Error occurred when attach to Activity:" + activity.getComponentName(), 71 e); 72 } 73 } else if (!(fragment instanceof LifecycleFragment)) { 74 Log.wtf( 75 LOG_TAG, 76 activity.getClass().getSimpleName() + " Incorrect instance on lifecycle fragment."); 77 return null; 78 } 79 return (LifecycleFragment) fragment; 80 } 81 } 82 } 83 84 return null; 85 } 86 87 @Override 88 public void onAttach(Context context) { 89 super.onAttach(context); 90 metricKey = MetricKey.get("ScreenDuration", getActivity().getClass().getSimpleName()); 91 } 92 93 @Override 94 public void onDetach() { 95 super.onDetach(); 96 SetupMetricsLogger.logDuration(getActivity(), metricKey, NANOSECONDS.toMillis(durationInNanos)); 97 } 98 99 @Override 100 public void onResume() { 101 super.onResume(); 102 startInNanos = ClockProvider.timeInNanos(); 103 } 104 105 @Override 106 public void onPause() { 107 super.onPause(); 108 durationInNanos += (ClockProvider.timeInNanos() - startInNanos); 109 } 110 } 111