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