From d21c97e9a74c67611891c6099c591955e4b996ef Mon Sep 17 00:00:00 2001 From: Sunny Shao Date: Thu, 8 Dec 2022 17:02:30 +0800 Subject: [PATCH] Add a new field elapsed_time_millis into Settings' atom - Add a new field elapsed_time_millis to keep the elapsed time since setup wizard finished. Fixes: 260660970 Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.core Change-Id: I28d13c4987ae1e4ef12eaff27e26a5121cf8093b --- .../android/settings/SettingsApplication.java | 2 + .../instrumentation/ElapsedTimeUtils.java | 89 +++++++++++++++++++ .../core/instrumentation/StatsLogWriter.java | 15 ++-- .../batteryusage/BootBroadcastReceiver.java | 4 + .../instrumentation/ElapsedTimeUtilsTest.java | 88 ++++++++++++++++++ 5 files changed, 193 insertions(+), 5 deletions(-) create mode 100644 src/com/android/settings/core/instrumentation/ElapsedTimeUtils.java create mode 100644 tests/robotests/src/com/android/settings/core/instrumentation/ElapsedTimeUtilsTest.java diff --git a/src/com/android/settings/SettingsApplication.java b/src/com/android/settings/SettingsApplication.java index 9c37d55478e..f06d99997a9 100644 --- a/src/com/android/settings/SettingsApplication.java +++ b/src/com/android/settings/SettingsApplication.java @@ -25,6 +25,7 @@ import android.util.FeatureFlagUtils; import androidx.window.embedding.SplitController; import com.android.settings.activityembedding.ActivityEmbeddingRulesController; +import com.android.settings.core.instrumentation.ElapsedTimeUtils; import com.android.settings.homepage.SettingsHomepageActivity; import com.android.settings.spa.SettingsSpaEnvironment; import com.android.settingslib.applications.AppIconCacheManager; @@ -42,6 +43,7 @@ public class SettingsApplication extends Application { @Override public void onCreate() { super.onCreate(); + ElapsedTimeUtils.assignSuwFinishedTimeStamp(this.getApplicationContext()); // Set Spa environment. setSpaEnvironment(); diff --git a/src/com/android/settings/core/instrumentation/ElapsedTimeUtils.java b/src/com/android/settings/core/instrumentation/ElapsedTimeUtils.java new file mode 100644 index 00000000000..5b09d5f4196 --- /dev/null +++ b/src/com/android/settings/core/instrumentation/ElapsedTimeUtils.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.core.instrumentation; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; + +import java.util.Optional; + +/** Class for calculating the elapsed time of the metrics. */ +public class ElapsedTimeUtils { + private static final String TAG = "ElapsedTimeUtils"; + private static final String ELAPSED_TIME_PREF_FILENAME = "elapsed_time_info"; + private static final String SUW_FINISHED_TIME_MS = "suw_finished_time_ms"; + private static Optional sSuwFinishedTimeStamp = Optional.empty();; + @VisibleForTesting + static final long DEFAULT_SETUP_TIME = -1L; + + /** + * Keeps the timestamp after SetupWizard finished. + * + * @param timestamp The timestamp of the SetupWizard finished. + */ + public static void storeSuwFinishedTimestamp(@NonNull Context context, long timestamp) { + final SharedPreferences sharedPrefs = getSharedPrefs(context); + if (!sharedPrefs.contains(SUW_FINISHED_TIME_MS)) { + sSuwFinishedTimeStamp = Optional.of(timestamp); + sharedPrefs.edit().putLong(SUW_FINISHED_TIME_MS, timestamp).apply(); + } + } + + /** + * Retrieves the preference value of SUW_FINISHED_TIME_MS and + * assigns to sSuwFinishedTimeStamp. + */ + public static void assignSuwFinishedTimeStamp(@NonNull Context context) { + final SharedPreferences sharedPrefs = getSharedPrefs(context); + if (sharedPrefs.contains(SUW_FINISHED_TIME_MS) && !sSuwFinishedTimeStamp.isPresent()) { + sSuwFinishedTimeStamp = Optional.of(getSuwFinishedTimestamp(context)); + } + } + + /** + * Gets the elapsed time by (timestamp - time of SetupWizard finished). + * @param timestamp The timestamp of the current time. + * @return The elapsed time after device setup finished. + */ + public static long getElapsedTime(long timestamp) { + if (!sSuwFinishedTimeStamp.isPresent()) { + Log.w(TAG, "getElapsedTime: sSuwFinishedTimeStamp is null"); + return DEFAULT_SETUP_TIME; + } + if (sSuwFinishedTimeStamp.get() != DEFAULT_SETUP_TIME) { + final long elapsedTime = timestamp - sSuwFinishedTimeStamp.get(); + return elapsedTime > 0L ? elapsedTime : DEFAULT_SETUP_TIME; + } + return DEFAULT_SETUP_TIME; + } + + @VisibleForTesting + static long getSuwFinishedTimestamp(Context context) { + return getSharedPrefs(context).getLong(SUW_FINISHED_TIME_MS, DEFAULT_SETUP_TIME); + } + + private static SharedPreferences getSharedPrefs(Context context) { + return context + .getApplicationContext() + .getSharedPreferences(ELAPSED_TIME_PREF_FILENAME, Context.MODE_PRIVATE); + } + + private ElapsedTimeUtils() {} +} diff --git a/src/com/android/settings/core/instrumentation/StatsLogWriter.java b/src/com/android/settings/core/instrumentation/StatsLogWriter.java index 7b5915afd62..2b17ba71d39 100644 --- a/src/com/android/settings/core/instrumentation/StatsLogWriter.java +++ b/src/com/android/settings/core/instrumentation/StatsLogWriter.java @@ -31,7 +31,8 @@ public class StatsLogWriter implements LogWriter { SettingsEnums.PAGE_VISIBLE /* action */, pageId, /* target pageId */ "" /* changedPreferenceKey */, - latency /* changedPreferenceIntValue */); + latency /* changedPreferenceIntValue */, + ElapsedTimeUtils.getElapsedTime(System.currentTimeMillis())); } @Override @@ -41,7 +42,8 @@ public class StatsLogWriter implements LogWriter { SettingsEnums.PAGE_HIDE /* action */, pageId, "" /* changedPreferenceKey */, - visibleTime /* changedPreferenceIntValue */); + visibleTime /* changedPreferenceIntValue */, + ElapsedTimeUtils.getElapsedTime(System.currentTimeMillis())); } @Override @@ -51,7 +53,8 @@ public class StatsLogWriter implements LogWriter { SettingsEnums.ACTION_SETTINGS_TILE_CLICK /* action */, SettingsEnums.PAGE_UNKNOWN /* pageId */, key /* changedPreferenceKey */, - 0 /* changedPreferenceIntValue */); + 0 /* changedPreferenceIntValue */, + ElapsedTimeUtils.getElapsedTime(System.currentTimeMillis())); } @Override @@ -61,7 +64,8 @@ public class StatsLogWriter implements LogWriter { SettingsEnums.ACTION_SETTINGS_PREFERENCE_CHANGE /* action */, SettingsEnums.PAGE_UNKNOWN /* pageId */, key /* changedPreferenceKey */, - value /* changedPreferenceIntValue */); + value /* changedPreferenceIntValue */, + ElapsedTimeUtils.getElapsedTime(System.currentTimeMillis())); } @Override @@ -107,6 +111,7 @@ public class StatsLogWriter implements LogWriter { action, pageId, key, - value); + value, + ElapsedTimeUtils.getElapsedTime(System.currentTimeMillis())); } } diff --git a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java index 5b48c9f83fa..c9d73cdbe70 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java @@ -23,6 +23,8 @@ import android.os.Handler; import android.os.Looper; import android.util.Log; +import com.android.settings.core.instrumentation.ElapsedTimeUtils; + import java.time.Duration; /** Receives broadcasts to start or stop the periodic fetching job. */ @@ -77,6 +79,8 @@ public final class BootBroadcastReceiver extends BroadcastReceiver { recheckIntent.setClass(context, BootBroadcastReceiver.class); mHandler.postDelayed(() -> context.sendBroadcast(recheckIntent), RESCHEDULE_FOR_BOOT_ACTION); + } else if (ACTION_SETUP_WIZARD_FINISHED.equals(action)) { + ElapsedTimeUtils.storeSuwFinishedTimestamp(context, System.currentTimeMillis()); } } diff --git a/tests/robotests/src/com/android/settings/core/instrumentation/ElapsedTimeUtilsTest.java b/tests/robotests/src/com/android/settings/core/instrumentation/ElapsedTimeUtilsTest.java new file mode 100644 index 00000000000..b334349ba1c --- /dev/null +++ b/tests/robotests/src/com/android/settings/core/instrumentation/ElapsedTimeUtilsTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.core.instrumentation; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class ElapsedTimeUtilsTest { + private Context mContext; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + } + + @Test + public void storeSuwFinishedTimestamp_firstTimeAccess_shouldStoreTimestamp() { + final long timestamp = 1000000L; + + ElapsedTimeUtils.storeSuwFinishedTimestamp(mContext, timestamp); + + final long result = ElapsedTimeUtils.getSuwFinishedTimestamp(mContext); + assertThat(result).isEqualTo(timestamp); + } + + @Test + public void storeSuwFinishedTimestamp_NotFirstTimeAccess_shouldNotStoreTimestamp() { + final long timestamp = 1000000L; + + ElapsedTimeUtils.storeSuwFinishedTimestamp(mContext, timestamp); + ElapsedTimeUtils.storeSuwFinishedTimestamp(mContext, 2000000L); + + final long result = ElapsedTimeUtils.getSuwFinishedTimestamp(mContext); + assertThat(result).isEqualTo(timestamp); + } + + @Test + public void getElapsedTime_valueInPrefs_positiveElapsedTime_returnElapsedTime() { + final long suwTime = 1000L; + final long actionTime = 2000L; + ElapsedTimeUtils.storeSuwFinishedTimestamp(mContext, suwTime); + + final long result = ElapsedTimeUtils.getElapsedTime(actionTime); + + assertThat(result).isEqualTo(actionTime - suwTime); + } + + @Test + public void getElapsedTime_valueInPrefs_negativeElapsedTime_returnDefault() { + final long suwTime = 2000L; + final long actionTime = 1000L; + ElapsedTimeUtils.storeSuwFinishedTimestamp(mContext, suwTime); + + final long result = ElapsedTimeUtils.getElapsedTime(actionTime); + + assertThat(result).isEqualTo(ElapsedTimeUtils.DEFAULT_SETUP_TIME); + } + + @Test + public void getElapsedTime_noValueInPrefs_returnDefault() { + final long actionTime = 1000L; + + final long result = ElapsedTimeUtils.getElapsedTime(actionTime); + + assertThat(result).isEqualTo(ElapsedTimeUtils.DEFAULT_SETUP_TIME); + } +}