From f815608a71497a9d3d59ad12fc724c14a96b4f4d Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Wed, 8 May 2024 17:08:57 +0000 Subject: [PATCH 1/4] UI and error message fixes for 16k developer option - Disallow disabling option when hardware offload values aren't default ones. This was bypassing warning dialogue - For ext4 format dialog, add a delete icon and change confirmation text - Change error message when update is pending. - Add padding to progress dialog Test: m Settings && adb install -r $ANDROID_PRODUCT_OUT/system_ext/priv-app/Settings/Settings.apk Bug: 295035851 Bug: 338139884 Change-Id: Ib1c3ac075a75a8515fe725103b062983ecf11fba --- .../DevelopmentSettingsDashboardFragment.java | 7 +++++++ .../Enable16kPagesPreferenceController.java | 10 +++++++--- .../settings/development/EnableExt4WarningDialog.java | 3 ++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java index 4038f4d8f0e..b1e4f8717e9 100644 --- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java @@ -376,6 +376,13 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra || enableAngleController.isDefaultValue())) { disableDeveloperOptions(); } else { + // Disabling developer options in page-agnostic mode isn't supported as device + // isn't in production state + if (Enable16kUtils.isPageAgnosticModeOn(getContext())) { + Enable16kUtils.showPageAgnosticWarning(getContext()); + onDisableDevelopmentOptionsRejected(); + return; + } DisableDevSettingsDialogFragment.show(this /* host */); } } diff --git a/src/com/android/settings/development/Enable16kPagesPreferenceController.java b/src/com/android/settings/development/Enable16kPagesPreferenceController.java index 23a6a22fdb1..0572b1b662d 100644 --- a/src/com/android/settings/development/Enable16kPagesPreferenceController.java +++ b/src/com/android/settings/development/Enable16kPagesPreferenceController.java @@ -207,7 +207,10 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen int status = data.getInt(SystemUpdateManager.KEY_STATUS); if (status != SystemUpdateManager.STATUS_UNKNOWN && status != SystemUpdateManager.STATUS_IDLE) { - throw new RuntimeException("System has pending update!"); + throw new RuntimeException( + "System has pending update! Please restart the device to complete applying" + + " pending update. If you are seeing this after using 16KB developer" + + " options, please check configuration and OTA packages!"); } // Publish system update info @@ -313,7 +316,7 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen } private void displayToast(String message) { - Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show(); + Toast.makeText(mContext, message, Toast.LENGTH_LONG).show(); } @Override @@ -330,7 +333,7 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen @Override public void onFailure(@NonNull Throwable t) { - Log.e(TAG, "Failed to change the /data partition with ext4"); + Log.e(TAG, "Failed to change the /data partition to ext4"); displayToast(mContext.getString(R.string.format_ext4_failure_toast)); } }, @@ -405,6 +408,7 @@ public class Enable16kPagesPreferenceController extends DeveloperOptionsPreferen LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); progressBar.setLayoutParams(params); + progressBar.setPadding(0, 24, 0, 24); builder.setView(progressBar); builder.setCancelable(false); return builder.create(); diff --git a/src/com/android/settings/development/EnableExt4WarningDialog.java b/src/com/android/settings/development/EnableExt4WarningDialog.java index c8ba521de2d..0e1dffd6643 100644 --- a/src/com/android/settings/development/EnableExt4WarningDialog.java +++ b/src/com/android/settings/development/EnableExt4WarningDialog.java @@ -70,8 +70,9 @@ public class EnableExt4WarningDialog extends InstrumentedDialogFragment public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { return new AlertDialog.Builder(getActivity()) .setTitle(R.string.confirm_format_ext4_title) + .setIcon(R.drawable.ic_delete_accent) .setMessage(R.string.confirm_format_ext4_text) - .setPositiveButton(android.R.string.ok, this /* onClickListener */) + .setPositiveButton(R.string.main_clear_confirm_title, this /* onClickListener */) .setNegativeButton(android.R.string.cancel, this /* onClickListener */) .create(); } From b9eb01643ca17e7f34f7858ce7ee527b6f9199e8 Mon Sep 17 00:00:00 2001 From: Chun-Ku Lin Date: Fri, 10 May 2024 00:26:56 +0000 Subject: [PATCH 2/4] Apply lineBreakWordStyle and hyphenationFrequency in EditShortcutScreen Uses the same style as mentioned in b/217659992 and b/232992171 Note: This doesn't fix the long word issue in Thai. This is the best we can get so far. Bug: 335749219 Test: manual (Can still see the EditShortcutScreen with no crash) Flag: EXEMPT resource only Change-Id: I3c1634de4a33c7ab6a80163217ef1cc65585c584 --- res/layout/accessibility_shortcut_option_checkable.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/res/layout/accessibility_shortcut_option_checkable.xml b/res/layout/accessibility_shortcut_option_checkable.xml index 15513520a7f..3218ca38655 100644 --- a/res/layout/accessibility_shortcut_option_checkable.xml +++ b/res/layout/accessibility_shortcut_option_checkable.xml @@ -48,6 +48,8 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="?android:attr/listPreferredItemPaddingStart" + android:hyphenationFrequency="normalFast" + android:lineBreakWordStyle="phrase" android:textAppearance="?android:attr/textAppearanceLarge" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@android:id/checkbox" @@ -58,6 +60,8 @@ android:id="@android:id/summary" android:layout_width="0dp" android:layout_height="wrap_content" + android:hyphenationFrequency="normalFast" + android:lineBreakWordStyle="phrase" android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="?android:attr/textColorSecondary" app:layout_constrainedHeight="true" From f44ea077d6b553c0122250525906a586cf61ae4f Mon Sep 17 00:00:00 2001 From: Fan Wu Date: Thu, 9 May 2024 11:08:05 +0800 Subject: [PATCH 3/4] Ignore existing failed tests and promote SettingsUnitTests to Presubmit. Exclude a few tests from Presubmit as they are failing in Presubmit but can pass locally. Bug: 339533415 Test: atest and presubmit Change-Id: Icdc94195f3b4dda4e523d4b7498698a5ada198ea --- TEST_MAPPING | 35 +++++++++---------- .../ApprovalPreferenceControllerTest.java | 2 ++ .../bluetooth/QrCodeScanModeActivityTest.java | 3 +- .../CommunalPreferenceControllerTest.java | 2 ++ .../ThreadNetworkFragmentControllerTest.kt | 2 ++ .../ThreadNetworkToggleControllerTest.kt | 3 ++ .../datausage/CellDataPreferenceTest.java | 2 ++ ...toothStackLogPreferenceControllerTest.java | 2 ++ .../SimStatusDialogControllerTest.java | 2 ++ .../storage/StorageAsyncLoaderTest.java | 2 ++ .../ScreenResolutionControllerTest.java | 3 ++ .../fuelgauge/batterytip/AppInfoTest.java | 2 ++ .../ContextualCardLookupTableTest.java | 2 ++ .../TermsOfAddressFeminineControllerTest.java | 2 ++ ...TermsOfAddressMasculineControllerTest.java | 2 ++ .../TermsOfAddressNeutralControllerTest.java | 2 ++ ...msOfAddressNotSpecifiedControllerTest.java | 2 ++ .../network/SubscriptionUtilTest.java | 1 + .../settings/network/UiccSlotUtilTest.java | 2 ++ .../network/telephony/CellInfoUtilTest.kt | 3 ++ ...edNetworkModePreferenceControllerTest.java | 5 +++ .../NetworkProviderWifiCallingGroupTest.java | 2 ++ ...vancedCallingPreferenceControllerTest.java | 2 ++ ...aSystemSelectPreferenceControllerTest.java | 4 +++ .../privacy/PrivacyDashboardActivityTest.java | 2 ++ 25 files changed, 71 insertions(+), 20 deletions(-) diff --git a/TEST_MAPPING b/TEST_MAPPING index f84565fa8ed..4b857526fd8 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -6,25 +6,22 @@ { "name": "SettingsUnitTests", "options": [ - { - "include-filter": "com.android.settings.biometrics" - }, - { - "include-filter": "com.android.settings.biometrics2" - }, - { - "include-filter": "com.android.settings.password" - }, - { - "include-filter": "com.android.settings.privatespace" - }, - { - "include-filter": "com.android.settings.safetycenter" - }, - { - "include-filter": "com.android.settings.security" - } - ] + { + "exclude-filter": "com.android.settings.fuelgauge.batterysaver" + }, + { + "exclude-filter": "com.android.settings.network.telephony" + }, + { + "exclude-filter": "com.android.settings.privatespace" + }, + { + "exclude-filter": "com.android.settings.regionalpreferences" + }, + { + "exclude-filter": "com.android.settings.vpn2" + } + ] } ], "postsubmit": [ diff --git a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java index eb236854450..ac86eb071f2 100644 --- a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/ApprovalPreferenceControllerTest.java @@ -50,6 +50,7 @@ import com.android.settingslib.RestrictedSwitchPreference; import org.junit.Assert; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -188,6 +189,7 @@ public class ApprovalPreferenceControllerTest { @Test @EnableFlags(Flags.FLAG_MODES_API) + @Ignore("b/339550695") public void disable() { mController.disable(mCn); verify(mFeatureFactory.metricsFeatureProvider).action( diff --git a/tests/unit/src/com/android/settings/bluetooth/QrCodeScanModeActivityTest.java b/tests/unit/src/com/android/settings/bluetooth/QrCodeScanModeActivityTest.java index 56764e3a145..ab77f2f31b6 100644 --- a/tests/unit/src/com/android/settings/bluetooth/QrCodeScanModeActivityTest.java +++ b/tests/unit/src/com/android/settings/bluetooth/QrCodeScanModeActivityTest.java @@ -18,7 +18,6 @@ package com.android.settings.bluetooth; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.content.Intent; @@ -28,11 +27,13 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.settingslib.bluetooth.BluetoothBroadcastUtils; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @RunWith(AndroidJUnit4.class) +@Ignore("b/337418017") public class QrCodeScanModeActivityTest { @Mock diff --git a/tests/unit/src/com/android/settings/communal/CommunalPreferenceControllerTest.java b/tests/unit/src/com/android/settings/communal/CommunalPreferenceControllerTest.java index 4d84765e188..6bd84f0064b 100644 --- a/tests/unit/src/com/android/settings/communal/CommunalPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/communal/CommunalPreferenceControllerTest.java @@ -32,12 +32,14 @@ import com.android.settings.Utils; import com.android.settings.testutils.ResourcesUtils; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) +@Ignore("b/337417918") public class CommunalPreferenceControllerTest { @Mock private UserManager mUserManager; diff --git a/tests/unit/src/com/android/settings/connecteddevice/threadnetwork/ThreadNetworkFragmentControllerTest.kt b/tests/unit/src/com/android/settings/connecteddevice/threadnetwork/ThreadNetworkFragmentControllerTest.kt index 0d57dafc144..d999464dddb 100644 --- a/tests/unit/src/com/android/settings/connecteddevice/threadnetwork/ThreadNetworkFragmentControllerTest.kt +++ b/tests/unit/src/com/android/settings/connecteddevice/threadnetwork/ThreadNetworkFragmentControllerTest.kt @@ -34,6 +34,7 @@ import org.junit.runner.RunWith import org.mockito.Mockito.mock import org.mockito.Mockito.spy import java.util.concurrent.Executor +import org.junit.Ignore /** Unit tests for [ThreadNetworkFragmentController]. */ @RunWith(AndroidJUnit4::class) @@ -99,6 +100,7 @@ class ThreadNetworkFragmentControllerTest { } @Test + @Ignore("b/339767488") fun getSummary_ThreadIsDisabled_returnsOff() { startController(controller) fakeThreadNetworkController.setEnabled(false, executor) {} diff --git a/tests/unit/src/com/android/settings/connecteddevice/threadnetwork/ThreadNetworkToggleControllerTest.kt b/tests/unit/src/com/android/settings/connecteddevice/threadnetwork/ThreadNetworkToggleControllerTest.kt index 329e7416d44..93ade562cfb 100644 --- a/tests/unit/src/com/android/settings/connecteddevice/threadnetwork/ThreadNetworkToggleControllerTest.kt +++ b/tests/unit/src/com/android/settings/connecteddevice/threadnetwork/ThreadNetworkToggleControllerTest.kt @@ -35,6 +35,7 @@ import org.junit.runner.RunWith import org.mockito.Mockito.mock import org.mockito.Mockito.spy import java.util.concurrent.Executor +import org.junit.Ignore /** Unit tests for [ThreadNetworkToggleController]. */ @RunWith(AndroidJUnit4::class) @@ -89,6 +90,7 @@ class ThreadNetworkToggleControllerTest { } @Test + @Ignore("b/339767488") fun isChecked_threadSetEnabled_returnsTrue() { fakeThreadNetworkController.setEnabled(true, executor) { } startController(controller) @@ -114,6 +116,7 @@ class ThreadNetworkToggleControllerTest { } @Test + @Ignore("b/339767488") fun setChecked_setUnchecked_threadIsDisabled() { startController(controller) diff --git a/tests/unit/src/com/android/settings/datausage/CellDataPreferenceTest.java b/tests/unit/src/com/android/settings/datausage/CellDataPreferenceTest.java index 93ca87577cf..60e09f3220c 100644 --- a/tests/unit/src/com/android/settings/datausage/CellDataPreferenceTest.java +++ b/tests/unit/src/com/android/settings/datausage/CellDataPreferenceTest.java @@ -28,12 +28,14 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) +@Ignore("b/337417779") public class CellDataPreferenceTest { @Mock diff --git a/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java b/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java index 0811f0499e3..ab1f46926fa 100644 --- a/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java @@ -37,12 +37,14 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) +@Ignore("b/339148064") public class BluetoothStackLogPreferenceControllerTest { private static final String TAG = "BluetoothStackLogPreferenceControllerTest"; diff --git a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java index 1eb670f5d21..556e1a7284e 100644 --- a/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java +++ b/tests/unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogControllerTest.java @@ -217,6 +217,7 @@ public class SimStatusDialogControllerTest { } @Test + @Ignore("b/337417520") public void initialize_updateServiceStateWithPowerOff_shouldUpdateTextAndResetSignalStrength() { when(mServiceState.getState()).thenReturn(ServiceState.STATE_POWER_OFF); @@ -229,6 +230,7 @@ public class SimStatusDialogControllerTest { } @Test + @Ignore("b/337417520") public void initialize_updateVoiceDataOutOfService_shouldUpdateSettingAndResetSignalStrength() { when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); when(mServiceState.getDataRegistrationState()).thenReturn( diff --git a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java index cad68e1d77c..9679275b77e 100644 --- a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java +++ b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java @@ -46,6 +46,7 @@ import com.android.settings.R; import com.android.settingslib.applications.StorageStatsSource; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -172,6 +173,7 @@ public class StorageAsyncLoaderTest { } @Test + @Ignore("b/337417819") public void testRemovedPackageDoesNotCrash() throws Exception { ApplicationInfo info = new ApplicationInfo(); info.packageName = PACKAGE_NAME_1; diff --git a/tests/unit/src/com/android/settings/display/ScreenResolutionControllerTest.java b/tests/unit/src/com/android/settings/display/ScreenResolutionControllerTest.java index b5df3a24472..ff1e137df12 100644 --- a/tests/unit/src/com/android/settings/display/ScreenResolutionControllerTest.java +++ b/tests/unit/src/com/android/settings/display/ScreenResolutionControllerTest.java @@ -30,6 +30,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.settings.core.BasePreferenceController; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -49,6 +50,7 @@ public class ScreenResolutionControllerTest { } @Test + @Ignore("b/337417619") public void getAvailabilityStatus_hasFhdAndQhdModes_returnAvailable() { Display.Mode modeA = new Display.Mode(0, mHighWidth, 0, 0); Display.Mode modeB = new Display.Mode(0, mFullWidth, 0, 0); @@ -76,6 +78,7 @@ public class ScreenResolutionControllerTest { } @Test + @Ignore("b/337417619") public void updateState_FullResolution_shouldSetSummaryToFullResolution() { int width = mFullWidth; doReturn(width).when(mController).getDisplayWidth(); diff --git a/tests/unit/src/com/android/settings/fuelgauge/batterytip/AppInfoTest.java b/tests/unit/src/com/android/settings/fuelgauge/batterytip/AppInfoTest.java index 069f1231a78..26288ab17fd 100644 --- a/tests/unit/src/com/android/settings/fuelgauge/batterytip/AppInfoTest.java +++ b/tests/unit/src/com/android/settings/fuelgauge/batterytip/AppInfoTest.java @@ -24,6 +24,7 @@ import android.text.format.DateUtils; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,6 +33,7 @@ import java.util.Collections; import java.util.List; @RunWith(AndroidJUnit4.class) +@Ignore("b/337418011") public class AppInfoTest { private static final String PACKAGE_NAME = "com.android.app"; diff --git a/tests/unit/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTableTest.java b/tests/unit/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTableTest.java index a7acffcaf9c..ddec83be87b 100644 --- a/tests/unit/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTableTest.java +++ b/tests/unit/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTableTest.java @@ -24,6 +24,7 @@ import com.android.settings.homepage.contextualcards.ContextualCardLookupTable.C import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -31,6 +32,7 @@ import java.util.ArrayList; import java.util.List; @RunWith(AndroidJUnit4.class) +@Ignore("b/337417898") public class ContextualCardLookupTableTest { private static final int UNSUPPORTED_CARD_TYPE = -99999; diff --git a/tests/unit/src/com/android/settings/localepicker/TermsOfAddressFeminineControllerTest.java b/tests/unit/src/com/android/settings/localepicker/TermsOfAddressFeminineControllerTest.java index ca39f8193b0..246fad62af9 100644 --- a/tests/unit/src/com/android/settings/localepicker/TermsOfAddressFeminineControllerTest.java +++ b/tests/unit/src/com/android/settings/localepicker/TermsOfAddressFeminineControllerTest.java @@ -34,6 +34,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.settings.widget.TickButtonPreference; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; @@ -92,6 +93,7 @@ public class TermsOfAddressFeminineControllerTest { } @Test + @Ignore("b/339543490") public void displayPreference_setGrammaticalGenderIsFeminine_FeminineIsSelected() { TickButtonPreference selectedPreference = (TickButtonPreference) mPreferenceScreen.getPreference(2); diff --git a/tests/unit/src/com/android/settings/localepicker/TermsOfAddressMasculineControllerTest.java b/tests/unit/src/com/android/settings/localepicker/TermsOfAddressMasculineControllerTest.java index c4575150597..f5ed3959b76 100644 --- a/tests/unit/src/com/android/settings/localepicker/TermsOfAddressMasculineControllerTest.java +++ b/tests/unit/src/com/android/settings/localepicker/TermsOfAddressMasculineControllerTest.java @@ -34,6 +34,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.settings.widget.TickButtonPreference; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; @@ -92,6 +93,7 @@ public class TermsOfAddressMasculineControllerTest { } @Test + @Ignore("b/339543490") public void displayPreference_setGrammaticalGenderIsMasculine_MasculineIsSelected() { TickButtonPreference selectedPreference = (TickButtonPreference) mPreferenceScreen.getPreference(3); diff --git a/tests/unit/src/com/android/settings/localepicker/TermsOfAddressNeutralControllerTest.java b/tests/unit/src/com/android/settings/localepicker/TermsOfAddressNeutralControllerTest.java index 757eb779ac0..0e53198188e 100644 --- a/tests/unit/src/com/android/settings/localepicker/TermsOfAddressNeutralControllerTest.java +++ b/tests/unit/src/com/android/settings/localepicker/TermsOfAddressNeutralControllerTest.java @@ -34,6 +34,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.settings.widget.TickButtonPreference; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; @@ -92,6 +93,7 @@ public class TermsOfAddressNeutralControllerTest { } @Test + @Ignore("b/339543490") public void displayPreference_setGrammaticalGenderIsNotSpecified_NeutralIsSelected() { TickButtonPreference selectedPreference = (TickButtonPreference) mPreferenceScreen.getPreference(4); diff --git a/tests/unit/src/com/android/settings/localepicker/TermsOfAddressNotSpecifiedControllerTest.java b/tests/unit/src/com/android/settings/localepicker/TermsOfAddressNotSpecifiedControllerTest.java index f53c5f68e6e..96bac08dde1 100644 --- a/tests/unit/src/com/android/settings/localepicker/TermsOfAddressNotSpecifiedControllerTest.java +++ b/tests/unit/src/com/android/settings/localepicker/TermsOfAddressNotSpecifiedControllerTest.java @@ -34,6 +34,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.settings.widget.TickButtonPreference; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; @@ -92,6 +93,7 @@ public class TermsOfAddressNotSpecifiedControllerTest { } @Test + @Ignore("b/339543490") public void displayPreference_setGrammaticalGenderIsNotSpecified_NotSpecifiedIsSelected() { TickButtonPreference selectedPreference = (TickButtonPreference) mPreferenceScreen.getPreference(1); diff --git a/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java b/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java index 0de09076683..f012388dc84 100644 --- a/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java +++ b/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java @@ -572,6 +572,7 @@ public class SubscriptionUtilTest { } @Test + @Ignore("b/339149463") public void isSimHardwareVisible_configAsVisible_returnTrue() { when(mResources.getBoolean(R.bool.config_show_sim_info)) .thenReturn(true); diff --git a/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java b/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java index 75c49b35016..1a895b3d0fd 100644 --- a/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java +++ b/tests/unit/src/com/android/settings/network/UiccSlotUtilTest.java @@ -41,6 +41,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.collect.ImmutableList; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -753,6 +754,7 @@ public class UiccSlotUtilTest { } @Test + @Ignore("b/337417975") public void onReceiveSimCardStateChangeReceiver_receiveAction_timerCountDown() { CountDownLatch latch = spy(new CountDownLatch(1)); UiccSlotUtil.SimCardStateChangeReceiver receive = diff --git a/tests/unit/src/com/android/settings/network/telephony/CellInfoUtilTest.kt b/tests/unit/src/com/android/settings/network/telephony/CellInfoUtilTest.kt index c3c61888d9b..d1d4a48d324 100644 --- a/tests/unit/src/com/android/settings/network/telephony/CellInfoUtilTest.kt +++ b/tests/unit/src/com/android/settings/network/telephony/CellInfoUtilTest.kt @@ -25,6 +25,7 @@ import com.android.internal.telephony.OperatorInfo import com.android.settings.network.telephony.CellInfoUtil.getNetworkTitle import com.android.settings.network.telephony.CellInfoUtil.getOperatorNumeric import com.google.common.truth.Truth.assertThat +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith @@ -96,6 +97,7 @@ class CellInfoUtilTest { } @Test + @Ignore("b/337417936") fun convertOperatorInfoToCellInfo() { val operatorInfo = OperatorInfo(LONG, SHORT, "12301") @@ -108,6 +110,7 @@ class CellInfoUtilTest { } @Test + @Ignore("b/337417222") fun cellInfoListToString() { val cellInfoList = listOf( diff --git a/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java index 1b337cadf8d..85c5c6b8f6c 100644 --- a/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java @@ -60,6 +60,7 @@ import com.android.settings.network.telephony.TelephonyConstants.TelephonyManage import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -346,6 +347,7 @@ public class EnabledNetworkModePreferenceControllerTest { @UiThreadTest @Test + @Ignore("b/337418033") public void updateState_updateByNetworkMode() { mockEnabledNetworkMode(TelephonyManagerConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA); @@ -377,6 +379,7 @@ public class EnabledNetworkModePreferenceControllerTest { @UiThreadTest @Test + @Ignore("b/337418033") public void onPreferenceChange_updateSuccess() { mockEnabledNetworkMode(TelephonyManagerConstants.NETWORK_MODE_LTE_GSM_WCDMA); doReturn(true).when(mTelephonyManager).setPreferredNetworkTypeBitmask( @@ -393,6 +396,7 @@ public class EnabledNetworkModePreferenceControllerTest { @UiThreadTest @Test + @Ignore("b/337418033") public void onPreferenceChange_updateFail() { mockEnabledNetworkMode(TelephonyManagerConstants.NETWORK_MODE_LTE_GSM_WCDMA); doReturn(false).when(mTelephonyManager).setPreferredNetworkTypeBitmask( @@ -408,6 +412,7 @@ public class EnabledNetworkModePreferenceControllerTest { @UiThreadTest @Test + @Ignore("b/337418033") public void preferredNetworkModeNotification_preferenceUpdates() { final PreferenceManager preferenceManager = new PreferenceManager(mContext); diff --git a/tests/unit/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroupTest.java b/tests/unit/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroupTest.java index 95f83900574..2165bc9a088 100644 --- a/tests/unit/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroupTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroupTest.java @@ -48,6 +48,7 @@ import com.android.settings.network.ims.MockWfcQueryImsState; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -176,6 +177,7 @@ public class NetworkProviderWifiCallingGroupTest { } @Test + @Ignore("b/337417499") public void shouldShowWifiCallingForSub_wifiCallingEnabledWithActivityHandleIntent_returnTrue() { buildPhoneAccountConfigureIntent(true); diff --git a/tests/unit/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceControllerTest.java index bed8ef1506f..e4c486f6487 100644 --- a/tests/unit/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/NrAdvancedCallingPreferenceControllerTest.java @@ -38,6 +38,7 @@ import com.android.settings.network.CarrierConfigCache; import com.android.settingslib.RestrictedSwitchPreference; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -180,6 +181,7 @@ public class NrAdvancedCallingPreferenceControllerTest { } @Test + @Ignore("b/339542743") public void updateState_configOn_prefChecked() { doReturn(TelephonyManager.ENABLE_VONR_SUCCESS).when( mTelephonyManager).setVoNrEnabled(anyBoolean()); diff --git a/tests/unit/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceControllerTest.java index 8cff38e1f31..2b886c19eab 100644 --- a/tests/unit/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/cdma/CdmaSystemSelectPreferenceControllerTest.java @@ -38,6 +38,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -99,6 +100,7 @@ public class CdmaSystemSelectPreferenceControllerTest { } @Test + @Ignore("b/337417544") public void updateState_stateHome_displayHome() { doReturn(TelephonyManager.CDMA_ROAMING_MODE_HOME).when( mTelephonyManager).getCdmaRoamingMode(); @@ -110,6 +112,7 @@ public class CdmaSystemSelectPreferenceControllerTest { } @Test + @Ignore("b/337417897") public void updateState_LteGSMWcdma_disabled() { doReturn(TelephonyManager.CDMA_ROAMING_MODE_HOME).when( mTelephonyManager).getCdmaRoamingMode(); @@ -123,6 +126,7 @@ public class CdmaSystemSelectPreferenceControllerTest { } @Test + @Ignore("b/337417917") public void updateState_stateOther_resetToDefault() { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.CDMA_ROAMING_MODE, diff --git a/tests/unit/src/com/android/settings/privacy/PrivacyDashboardActivityTest.java b/tests/unit/src/com/android/settings/privacy/PrivacyDashboardActivityTest.java index ae42c849837..99e9ab95c8c 100644 --- a/tests/unit/src/com/android/settings/privacy/PrivacyDashboardActivityTest.java +++ b/tests/unit/src/com/android/settings/privacy/PrivacyDashboardActivityTest.java @@ -36,6 +36,7 @@ import com.android.settings.SettingsActivity; import com.android.settings.safetycenter.SafetyCenterManagerWrapper; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -58,6 +59,7 @@ public class PrivacyDashboardActivityTest { } @Test + @Ignore("b/339544085") public void onCreate_whenSafetyCenterEnabled_redirectsToSafetyCenter() throws Exception { startActivityUsingIntent(android.provider.Settings.ACTION_PRIVACY_SETTINGS); when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(true); From ee501485b86708a181ecf28a6030999160b493ff Mon Sep 17 00:00:00 2001 From: mxyyiyi Date: Sat, 11 May 2024 16:31:33 +0800 Subject: [PATCH 4/4] Schedule periodic job in next full-hour timestamp under local timezone. Bug:315228870 Test: atest SettingsRoboTests:com.android.settings.fuelgauge.batteryusage.PeriodicJobManagerTest Change-Id: I1d2b298ea53c1018b5f94b5ba00692055374eef2 --- .../batteryusage/PeriodicJobManager.java | 33 +++-- .../batteryusage/PeriodicJobManagerTest.java | 114 +++++++++++++++--- 2 files changed, 112 insertions(+), 35 deletions(-) diff --git a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java index b2c72bf1406..c2dcb99a994 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java +++ b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java @@ -28,7 +28,6 @@ import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action; import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils; import com.android.settings.overlay.FeatureFactory; -import java.time.Clock; import java.time.Duration; /** Manages the periodic job to schedule or cancel the next job. */ @@ -41,8 +40,6 @@ public final class PeriodicJobManager { private final Context mContext; private final AlarmManager mAlarmManager; - @VisibleForTesting static final int DATA_FETCH_INTERVAL_MINUTE = 60; - @VisibleForTesting static long sBroadcastDelayFromBoot = Duration.ofMinutes(40).toMillis(); @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @@ -76,20 +73,21 @@ public final class PeriodicJobManager { // Cancels the previous alert job and schedules the next one. final PendingIntent pendingIntent = getPendingIntent(); cancelJob(pendingIntent); - // Uses UTC time to avoid scheduler is impacted by different timezone. - final long triggerAtMillis = getTriggerAtMillis(mContext, Clock.systemUTC(), fromBoot); + // Uses the timestamp of next full hour in local timezone. + long currentTimeMillis = System.currentTimeMillis(); + final long triggerAtMillis = getTriggerAtMillis(currentTimeMillis, fromBoot); mAlarmManager.setExactAndAllowWhileIdle( AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent); - final String utcToLocalTime = ConvertUtils.utcToLocalTimeForLogging(triggerAtMillis); + final String timeForLogging = ConvertUtils.utcToLocalTimeForLogging(triggerAtMillis); BatteryUsageLogUtils.writeLog( mContext, Action.SCHEDULE_JOB, - String.format("triggerTime=%s, fromBoot=%b", utcToLocalTime, fromBoot)); - Log.d(TAG, "schedule next alarm job at " + utcToLocalTime); + String.format("triggerTime=%s, fromBoot=%b", timeForLogging, fromBoot)); + Log.d(TAG, "schedule next alarm job at " + timeForLogging); } - void cancelJob(PendingIntent pendingIntent) { + private void cancelJob(PendingIntent pendingIntent) { if (mAlarmManager != null) { mAlarmManager.cancel(pendingIntent); } else { @@ -97,22 +95,21 @@ public final class PeriodicJobManager { } } - /** Gets the next alarm trigger UTC time in milliseconds. */ - static long getTriggerAtMillis(Context context, Clock clock, final boolean fromBoot) { - long currentTimeMillis = clock.millis(); + /** Gets the next alarm trigger time in milliseconds. */ + @VisibleForTesting + static long getTriggerAtMillis(final long currentTimeMillis, final boolean fromBoot) { final boolean delayHourlyJobWhenBooting = FeatureFactory.getFeatureFactory() .getPowerUsageFeatureProvider() .delayHourlyJobWhenBooting(); - // Rounds to the previous nearest time slot and shifts to the next one. - long timeSlotUnit = Duration.ofMinutes(DATA_FETCH_INTERVAL_MINUTE).toMillis(); - long targetTime = (currentTimeMillis / timeSlotUnit) * timeSlotUnit + timeSlotUnit; + long targetTimeMillis = TimestampUtils.getNextHourTimestamp(currentTimeMillis); if (delayHourlyJobWhenBooting && fromBoot - && (targetTime - currentTimeMillis) <= sBroadcastDelayFromBoot) { - targetTime += timeSlotUnit; + && (targetTimeMillis - currentTimeMillis) <= sBroadcastDelayFromBoot) { + // Skips this time broadcast, schedule in the next alarm trigger. + targetTimeMillis = TimestampUtils.getNextHourTimestamp(targetTimeMillis); } - return targetTime; + return targetTimeMillis; } private PendingIntent getPendingIntent() { diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManagerTest.java index 69905354a52..7c2abd86d57 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManagerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManagerTest.java @@ -18,6 +18,7 @@ package com.android.settings.fuelgauge.batteryusage; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; import static org.robolectric.Shadows.shadowOf; import android.app.AlarmManager; @@ -25,7 +26,7 @@ import android.content.Context; import androidx.test.core.app.ApplicationProvider; -import com.android.settings.testutils.FakeClock; +import com.android.settings.testutils.FakeFeatureFactory; import org.junit.After; import org.junit.Before; @@ -35,6 +36,8 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.shadows.ShadowAlarmManager; import java.time.Duration; +import java.util.Calendar; +import java.util.TimeZone; /** Tests of {@link PeriodicJobManager}. */ @RunWith(RobolectricTestRunner.class) @@ -42,11 +45,14 @@ public final class PeriodicJobManagerTest { private Context mContext; private ShadowAlarmManager mShadowAlarmManager; private PeriodicJobManager mPeriodicJobManager; + private FakeFeatureFactory mFeatureFactory; @Before public void setUp() { mContext = ApplicationProvider.getApplicationContext(); mPeriodicJobManager = PeriodicJobManager.getInstance(mContext); + mFeatureFactory = FakeFeatureFactory.setupForTest(); + doReturn(false).when(mFeatureFactory.powerUsageFeatureProvider).delayHourlyJobWhenBooting(); mShadowAlarmManager = shadowOf(mContext.getSystemService(AlarmManager.class)); } @@ -68,28 +74,102 @@ public final class PeriodicJobManagerTest { } @Test - public void getTriggerAtMillis_withoutOffset_returnsExpectedResult() { - long timeSlotUnit = PeriodicJobManager.DATA_FETCH_INTERVAL_MINUTE; - // Sets the current time. - Duration currentTimeDuration = Duration.ofMinutes(timeSlotUnit * 2); - FakeClock fakeClock = new FakeClock(); - fakeClock.setCurrentTime(currentTimeDuration); + public void getTriggerAtMillis_halfFullHourTimeZoneWithoutOffset_returnsExpectedResult() { + final int minutesOffset = 0; + final long currentTimestamp = + setTimeZoneAndGenerateTestTimestamp(/* isFullHourTimeZone= */ false, minutesOffset); + final long expectedTimestamp = + currentTimestamp + Duration.ofMinutes(60 - minutesOffset).toMillis(); assertThat( PeriodicJobManager.getTriggerAtMillis( - mContext, fakeClock, /* fromBoot= */ false)) - .isEqualTo(currentTimeDuration.plusMinutes(timeSlotUnit).toMillis()); + /* currentTimeMillis= */ currentTimestamp, /* fromBoot= */ false)) + .isEqualTo(expectedTimestamp); } @Test - public void getTriggerAtMillis_withOffset_returnsExpectedResult() { - long timeSlotUnit = PeriodicJobManager.DATA_FETCH_INTERVAL_MINUTE; - // Sets the current time. - Duration currentTimeDuration = Duration.ofMinutes(timeSlotUnit * 2); - FakeClock fakeClock = new FakeClock(); - fakeClock.setCurrentTime(currentTimeDuration.plusMinutes(1L).plusMillis(51L)); + public void getTriggerAtMillis_halfFullHourTimeZoneWithOffset_returnsExpectedResult() { + final int minutesOffset = 21; + final long currentTimestamp = + setTimeZoneAndGenerateTestTimestamp(/* isFullHourTimeZone= */ false, minutesOffset); + final long expectedTimestamp = + currentTimestamp + Duration.ofMinutes(60 - minutesOffset).toMillis(); - assertThat(PeriodicJobManager.getTriggerAtMillis(mContext, fakeClock, /* fromBoot= */ true)) - .isEqualTo(currentTimeDuration.plusMinutes(timeSlotUnit).toMillis()); + assertThat( + PeriodicJobManager.getTriggerAtMillis( + /* currentTimeMillis= */ currentTimestamp, /* fromBoot= */ false)) + .isEqualTo(expectedTimestamp); + } + + @Test + public void getTriggerAtMillis_halfFullHourTimeZoneWithBroadcastDelay_returnsExpectedResult() { + doReturn(true).when(mFeatureFactory.powerUsageFeatureProvider).delayHourlyJobWhenBooting(); + + final int minutesOffset = 21; + final long currentTimestamp = + setTimeZoneAndGenerateTestTimestamp(/* isFullHourTimeZone= */ false, minutesOffset); + final long expectedTimestamp = + currentTimestamp + Duration.ofMinutes(60 * 2 - minutesOffset).toMillis(); + + assertThat( + PeriodicJobManager.getTriggerAtMillis( + /* currentTimeMillis= */ currentTimestamp, /* fromBoot= */ true)) + .isEqualTo(expectedTimestamp); + } + + @Test + public void getTriggerAtMillis_fullHourTimeZoneWithoutOffset_returnsExpectedResult() { + final int minutesOffset = 0; + final long currentTimestamp = + setTimeZoneAndGenerateTestTimestamp(/* isFullHourTimeZone= */ true, minutesOffset); + final long expectedTimestamp = + currentTimestamp + Duration.ofMinutes(60 - minutesOffset).toMillis(); + + assertThat( + PeriodicJobManager.getTriggerAtMillis( + /* currentTimeMillis= */ currentTimestamp, /* fromBoot= */ false)) + .isEqualTo(expectedTimestamp); + } + + @Test + public void getTriggerAtMillis_fullHourTimeZoneWithOffset_returnsExpectedResult() { + final int minutesOffset = 21; + final long currentTimestamp = + setTimeZoneAndGenerateTestTimestamp(/* isFullHourTimeZone= */ true, minutesOffset); + final long expectedTimestamp = + currentTimestamp + Duration.ofMinutes(60 - minutesOffset).toMillis(); + + assertThat( + PeriodicJobManager.getTriggerAtMillis( + /* currentTimeMillis= */ currentTimestamp, /* fromBoot= */ false)) + .isEqualTo(expectedTimestamp); + } + + @Test + public void getTriggerAtMillis_fullHourTimeZoneWithBroadcastDelay_returnsExpectedResult() { + doReturn(true).when(mFeatureFactory.powerUsageFeatureProvider).delayHourlyJobWhenBooting(); + + final int minutesOffset = 21; + final long currentTimestamp = + setTimeZoneAndGenerateTestTimestamp(/* isFullHourTimeZone= */ true, minutesOffset); + final long expectedTimestamp = + currentTimestamp + Duration.ofMinutes(60 * 2 - minutesOffset).toMillis(); + + assertThat( + PeriodicJobManager.getTriggerAtMillis( + /* currentTimeMillis= */ currentTimestamp, /* fromBoot= */ true)) + .isEqualTo(expectedTimestamp); + } + + private static long setTimeZoneAndGenerateTestTimestamp( + final boolean isFullHourTimeZone, final int minutesOffset) { + final TimeZone timeZone = + TimeZone.getTimeZone(isFullHourTimeZone ? "UTC" : /* GMT+05:30 */ "Asia/Kalkata"); + TimeZone.setDefault(timeZone); + Calendar calendar = (Calendar) Calendar.getInstance().clone(); + calendar.set(Calendar.MINUTE, minutesOffset); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + return calendar.getTimeInMillis(); } }