• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
LifecycleFragment()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    */
attachNow(Activity activity)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
onAttach(Context context)88   public void onAttach(Context context) {
89     super.onAttach(context);
90     metricKey = MetricKey.get("ScreenDuration", getActivity().getClass().getSimpleName());
91   }
92 
93   @Override
onDetach()94   public void onDetach() {
95     super.onDetach();
96     SetupMetricsLogger.logDuration(getActivity(), metricKey, NANOSECONDS.toMillis(durationInNanos));
97   }
98 
99   @Override
onResume()100   public void onResume() {
101     super.onResume();
102     startInNanos = ClockProvider.timeInNanos();
103   }
104 
105   @Override
onPause()106   public void onPause() {
107     super.onPause();
108     durationInNanos += (ClockProvider.timeInNanos() - startInNanos);
109   }
110 }
111