Loading core/java/android/service/timezone/ITimeZoneProviderManager.aidl +2 −4 Original line number Diff line number Diff line Loading @@ -16,13 +16,11 @@ package android.service.timezone; import android.service.timezone.TimeZoneProviderSuggestion; import android.service.timezone.TimeZoneProviderEvent; /** * @hide */ oneway interface ITimeZoneProviderManager { void onTimeZoneProviderSuggestion(in TimeZoneProviderSuggestion timeZoneProviderSuggestion); void onTimeZoneProviderUncertain(); void onTimeZoneProviderPermanentFailure(in String failureReason); void onTimeZoneProviderEvent(in TimeZoneProviderEvent timeZoneProviderEvent); } core/java/android/service/timezone/TimeZoneProviderEvent.aidl 0 → 100644 +22 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021, 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 android.service.timezone; /** * @hide */ parcelable TimeZoneProviderEvent; services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderEvent.java→core/java/android/service/timezone/TimeZoneProviderEvent.java +57 −5 Original line number Diff line number Diff line Loading @@ -14,13 +14,13 @@ * limitations under the License. */ package com.android.server.timezonedetector.location; package android.service.timezone; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.service.timezone.TimeZoneProviderService; import android.service.timezone.TimeZoneProviderSuggestion; import android.os.Parcel; import android.os.Parcelable; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; Loading @@ -29,9 +29,11 @@ import java.lang.annotation.Target; import java.util.Objects; /** * An event from a {@link TimeZoneProviderService}. * Encapsulates a reported event from a {@link TimeZoneProviderService}. * * @hide */ final class TimeZoneProviderEvent { public final class TimeZoneProviderEvent implements Parcelable { @IntDef(prefix = "EVENT_TYPE_", value = { EVENT_TYPE_PERMANENT_FAILURE, EVENT_TYPE_SUGGESTION, EVENT_TYPE_UNCERTAIN }) Loading Loading @@ -118,6 +120,35 @@ final class TimeZoneProviderEvent { return mFailureCause; } public static final @NonNull Creator<TimeZoneProviderEvent> CREATOR = new Creator<TimeZoneProviderEvent>() { @Override public TimeZoneProviderEvent createFromParcel(Parcel in) { int type = in.readInt(); TimeZoneProviderSuggestion suggestion = in.readParcelable(getClass().getClassLoader()); String failureCause = in.readString8(); return new TimeZoneProviderEvent(type, suggestion, failureCause); } @Override public TimeZoneProviderEvent[] newArray(int size) { return new TimeZoneProviderEvent[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel parcel, int flags) { parcel.writeInt(mType); parcel.writeParcelable(mSuggestion, 0); parcel.writeString8(mFailureCause); } @Override public String toString() { return "TimeZoneProviderEvent{" Loading @@ -127,6 +158,27 @@ final class TimeZoneProviderEvent { + '}'; } /** * Similar to {@link #equals} except this methods checks for equivalence, not equality. * i.e. two {@link #EVENT_TYPE_UNCERTAIN} and {@link #EVENT_TYPE_PERMANENT_FAILURE} events are * always equivalent, two {@link #EVENT_TYPE_SUGGESTION} events are equivalent if they suggest * the same time zones. */ @SuppressWarnings("ReferenceEquality") public boolean isEquivalentTo(@Nullable TimeZoneProviderEvent other) { if (this == other) { return true; } if (other == null || mType != other.mType) { return false; } if (mType == EVENT_TYPE_SUGGESTION) { // Only check the time zone IDs. The times will be different, but we don't mind. return mSuggestion.getTimeZoneIds().equals(other.getSuggestion().getTimeZoneIds()); } return true; } @Override public boolean equals(Object o) { if (this == o) { Loading core/java/android/service/timezone/TimeZoneProviderService.java +77 −23 Original line number Diff line number Diff line Loading @@ -28,8 +28,11 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BackgroundThread; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Objects; /** Loading Loading @@ -122,7 +125,9 @@ import java.util.Objects; * #onDestroy()} can occur on a different thread from those made to {@link * TimeZoneProviderService}-defined service methods, so implementations must be defensive and not * assume an ordering between them, e.g. a call to {@link #onStopUpdates()} can occur after {@link * #onDestroy()} and should be handled safely. * #onDestroy()} and should be handled safely. {@link #mLock} is used to ensure that synchronous * calls like {@link #dump(FileDescriptor, PrintWriter, String[])} are safe with respect to * asynchronous behavior. * * @hide */ Loading Loading @@ -162,12 +167,26 @@ public abstract class TimeZoneProviderService extends Service { private final TimeZoneProviderServiceWrapper mWrapper = new TimeZoneProviderServiceWrapper(); /** The object used for operations that occur between the main / handler thread. */ private final Object mLock = new Object(); /** The handler used for most operations. */ private final Handler mHandler = BackgroundThread.getHandler(); /** Set by {@link #mHandler} thread. */ @GuardedBy("mLock") @Nullable private ITimeZoneProviderManager mManager; /** * The type of the last suggestion sent to the system server. Used to de-dupe suggestions client * side and avoid calling into the system server unnecessarily. {@code null} means no previous * event has been sent this cycle; this field is cleared when the service is started. */ @GuardedBy("mLock") @Nullable private TimeZoneProviderEvent mLastEventSent; @Override @NonNull public final IBinder onBind(@NonNull Intent intent) { Loading @@ -182,14 +201,21 @@ public abstract class TimeZoneProviderService extends Service { Objects.requireNonNull(suggestion); mHandler.post(() -> { synchronized (mLock) { ITimeZoneProviderManager manager = mManager; if (manager != null) { try { manager.onTimeZoneProviderSuggestion(suggestion); TimeZoneProviderEvent thisEvent = TimeZoneProviderEvent.createSuggestionEvent(suggestion); if (!thisEvent.isEquivalentTo(mLastEventSent)) { manager.onTimeZoneProviderEvent(thisEvent); mLastEventSent = thisEvent; } } catch (RemoteException | RuntimeException e) { Log.w(TAG, e); } } } }); } Loading @@ -200,14 +226,21 @@ public abstract class TimeZoneProviderService extends Service { */ public final void reportUncertain() { mHandler.post(() -> { synchronized (mLock) { ITimeZoneProviderManager manager = mManager; if (manager != null) { try { manager.onTimeZoneProviderUncertain(); TimeZoneProviderEvent thisEvent = TimeZoneProviderEvent.createUncertainEvent(); if (!thisEvent.isEquivalentTo(mLastEventSent)) { manager.onTimeZoneProviderEvent(thisEvent); mLastEventSent = thisEvent; } } catch (RemoteException | RuntimeException e) { Log.w(TAG, e); } } } }); } Loading @@ -219,22 +252,33 @@ public abstract class TimeZoneProviderService extends Service { Objects.requireNonNull(cause); mHandler.post(() -> { synchronized (mLock) { ITimeZoneProviderManager manager = mManager; if (manager != null) { try { manager.onTimeZoneProviderPermanentFailure(cause.getMessage()); String causeString = cause.getMessage(); TimeZoneProviderEvent thisEvent = TimeZoneProviderEvent.createPermanentFailureEvent(causeString); if (!thisEvent.isEquivalentTo(mLastEventSent)) { manager.onTimeZoneProviderEvent(thisEvent); mLastEventSent = thisEvent; } } catch (RemoteException | RuntimeException e) { Log.w(TAG, e); } } } }); } private void onStartUpdatesInternal(@NonNull ITimeZoneProviderManager manager, @DurationMillisLong long initializationTimeoutMillis) { synchronized (mLock) { mManager = manager; mLastEventSent = null; onStartUpdates(initializationTimeoutMillis); } } /** * Informs the provider that it should start detecting and reporting the detected time zone Loading Loading @@ -265,9 +309,11 @@ public abstract class TimeZoneProviderService extends Service { public abstract void onStartUpdates(@DurationMillisLong long initializationTimeoutMillis); private void onStopUpdatesInternal() { synchronized (mLock) { onStopUpdates(); mManager = null; } } /** * Stops the provider sending further updates. This will be called after {@link Loading @@ -275,6 +321,14 @@ public abstract class TimeZoneProviderService extends Service { */ public abstract void onStopUpdates(); /** @hide */ @Override protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { synchronized (mLock) { writer.append("mLastEventSent=" + mLastEventSent); } } private class TimeZoneProviderServiceWrapper extends ITimeZoneProvider.Stub { public void startUpdates(@NonNull ITimeZoneProviderManager manager, Loading core/tests/coretests/src/android/service/timezone/TimeZoneProviderEventTest.java 0 → 100644 +149 −0 Original line number Diff line number Diff line /* * Copyright 2021 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 android.service.timezone; import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.junit.Test; import java.util.Arrays; import java.util.Collections; public class TimeZoneProviderEventTest { @Test public void isEquivalentToAndEquals() { TimeZoneProviderEvent fail1v1 = TimeZoneProviderEvent.createPermanentFailureEvent("one"); assertEquals(fail1v1, fail1v1); assertIsEquivalentTo(fail1v1, fail1v1); assertNotEquals(fail1v1, null); assertNotEquivalentTo(fail1v1, null); { TimeZoneProviderEvent fail1v2 = TimeZoneProviderEvent.createPermanentFailureEvent("one"); assertEquals(fail1v1, fail1v2); assertIsEquivalentTo(fail1v1, fail1v2); TimeZoneProviderEvent fail2 = TimeZoneProviderEvent.createPermanentFailureEvent("two"); assertNotEquals(fail1v1, fail2); assertIsEquivalentTo(fail1v1, fail2); } TimeZoneProviderEvent uncertain1v1 = TimeZoneProviderEvent.createUncertainEvent(); assertEquals(uncertain1v1, uncertain1v1); assertIsEquivalentTo(uncertain1v1, uncertain1v1); assertNotEquals(uncertain1v1, null); assertNotEquivalentTo(uncertain1v1, null); { TimeZoneProviderEvent uncertain1v2 = TimeZoneProviderEvent.createUncertainEvent(); assertEquals(uncertain1v1, uncertain1v2); assertIsEquivalentTo(uncertain1v1, uncertain1v2); } TimeZoneProviderSuggestion suggestion1 = new TimeZoneProviderSuggestion.Builder() .setElapsedRealtimeMillis(1111L) .setTimeZoneIds(Collections.singletonList("Europe/London")) .build(); TimeZoneProviderEvent certain1v1 = TimeZoneProviderEvent.createSuggestionEvent(suggestion1); assertEquals(certain1v1, certain1v1); assertIsEquivalentTo(certain1v1, certain1v1); assertNotEquals(certain1v1, null); assertNotEquivalentTo(certain1v1, null); { TimeZoneProviderEvent certain1v2 = TimeZoneProviderEvent.createSuggestionEvent(suggestion1); assertEquals(certain1v1, certain1v2); assertIsEquivalentTo(certain1v1, certain1v2); TimeZoneProviderSuggestion suggestion2 = new TimeZoneProviderSuggestion.Builder() .setElapsedRealtimeMillis(2222L) .setTimeZoneIds(Collections.singletonList("Europe/London")) .build(); assertNotEquals(suggestion1, suggestion2); TimeZoneProviderEvent certain2 = TimeZoneProviderEvent.createSuggestionEvent(suggestion2); assertNotEquals(certain1v1, certain2); assertIsEquivalentTo(certain1v1, certain2); TimeZoneProviderSuggestion suggestion3 = new TimeZoneProviderSuggestion.Builder() .setTimeZoneIds(Collections.singletonList("Europe/Paris")) .build(); TimeZoneProviderEvent certain3 = TimeZoneProviderEvent.createSuggestionEvent(suggestion3); assertNotEquals(certain1v1, certain3); assertNotEquivalentTo(certain1v1, certain3); } assertNotEquals(fail1v1, uncertain1v1); assertNotEquivalentTo(fail1v1, uncertain1v1); assertNotEquals(fail1v1, certain1v1); assertNotEquivalentTo(fail1v1, certain1v1); } @Test public void testParcelable_failureEvent() { TimeZoneProviderEvent event = TimeZoneProviderEvent.createPermanentFailureEvent("failure reason"); assertRoundTripParcelable(event); } @Test public void testParcelable_uncertain() { TimeZoneProviderEvent event = TimeZoneProviderEvent.createUncertainEvent(); assertRoundTripParcelable(event); } @Test public void testParcelable_suggestion() { TimeZoneProviderSuggestion suggestion = new TimeZoneProviderSuggestion.Builder() .setTimeZoneIds(Arrays.asList("Europe/London", "Europe/Paris")) .build(); TimeZoneProviderEvent event = TimeZoneProviderEvent.createSuggestionEvent(suggestion); assertRoundTripParcelable(event); } private static void assertNotEquivalentTo( TimeZoneProviderEvent one, TimeZoneProviderEvent two) { if (one == null && two == null) { fail("null arguments"); } if (one != null) { assertFalse("one=" + one + ", two=" + two, one.isEquivalentTo(two)); } if (two != null) { assertFalse("one=" + one + ", two=" + two, two.isEquivalentTo(one)); } } private static void assertIsEquivalentTo(TimeZoneProviderEvent one, TimeZoneProviderEvent two) { if (one == null || two == null) { fail("null arguments"); } assertTrue("one=" + one + ", two=" + two, one.isEquivalentTo(two)); assertTrue("one=" + one + ", two=" + two, two.isEquivalentTo(one)); } } Loading
core/java/android/service/timezone/ITimeZoneProviderManager.aidl +2 −4 Original line number Diff line number Diff line Loading @@ -16,13 +16,11 @@ package android.service.timezone; import android.service.timezone.TimeZoneProviderSuggestion; import android.service.timezone.TimeZoneProviderEvent; /** * @hide */ oneway interface ITimeZoneProviderManager { void onTimeZoneProviderSuggestion(in TimeZoneProviderSuggestion timeZoneProviderSuggestion); void onTimeZoneProviderUncertain(); void onTimeZoneProviderPermanentFailure(in String failureReason); void onTimeZoneProviderEvent(in TimeZoneProviderEvent timeZoneProviderEvent); }
core/java/android/service/timezone/TimeZoneProviderEvent.aidl 0 → 100644 +22 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021, 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 android.service.timezone; /** * @hide */ parcelable TimeZoneProviderEvent;
services/core/java/com/android/server/timezonedetector/location/TimeZoneProviderEvent.java→core/java/android/service/timezone/TimeZoneProviderEvent.java +57 −5 Original line number Diff line number Diff line Loading @@ -14,13 +14,13 @@ * limitations under the License. */ package com.android.server.timezonedetector.location; package android.service.timezone; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.service.timezone.TimeZoneProviderService; import android.service.timezone.TimeZoneProviderSuggestion; import android.os.Parcel; import android.os.Parcelable; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; Loading @@ -29,9 +29,11 @@ import java.lang.annotation.Target; import java.util.Objects; /** * An event from a {@link TimeZoneProviderService}. * Encapsulates a reported event from a {@link TimeZoneProviderService}. * * @hide */ final class TimeZoneProviderEvent { public final class TimeZoneProviderEvent implements Parcelable { @IntDef(prefix = "EVENT_TYPE_", value = { EVENT_TYPE_PERMANENT_FAILURE, EVENT_TYPE_SUGGESTION, EVENT_TYPE_UNCERTAIN }) Loading Loading @@ -118,6 +120,35 @@ final class TimeZoneProviderEvent { return mFailureCause; } public static final @NonNull Creator<TimeZoneProviderEvent> CREATOR = new Creator<TimeZoneProviderEvent>() { @Override public TimeZoneProviderEvent createFromParcel(Parcel in) { int type = in.readInt(); TimeZoneProviderSuggestion suggestion = in.readParcelable(getClass().getClassLoader()); String failureCause = in.readString8(); return new TimeZoneProviderEvent(type, suggestion, failureCause); } @Override public TimeZoneProviderEvent[] newArray(int size) { return new TimeZoneProviderEvent[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel parcel, int flags) { parcel.writeInt(mType); parcel.writeParcelable(mSuggestion, 0); parcel.writeString8(mFailureCause); } @Override public String toString() { return "TimeZoneProviderEvent{" Loading @@ -127,6 +158,27 @@ final class TimeZoneProviderEvent { + '}'; } /** * Similar to {@link #equals} except this methods checks for equivalence, not equality. * i.e. two {@link #EVENT_TYPE_UNCERTAIN} and {@link #EVENT_TYPE_PERMANENT_FAILURE} events are * always equivalent, two {@link #EVENT_TYPE_SUGGESTION} events are equivalent if they suggest * the same time zones. */ @SuppressWarnings("ReferenceEquality") public boolean isEquivalentTo(@Nullable TimeZoneProviderEvent other) { if (this == other) { return true; } if (other == null || mType != other.mType) { return false; } if (mType == EVENT_TYPE_SUGGESTION) { // Only check the time zone IDs. The times will be different, but we don't mind. return mSuggestion.getTimeZoneIds().equals(other.getSuggestion().getTimeZoneIds()); } return true; } @Override public boolean equals(Object o) { if (this == o) { Loading
core/java/android/service/timezone/TimeZoneProviderService.java +77 −23 Original line number Diff line number Diff line Loading @@ -28,8 +28,11 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BackgroundThread; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Objects; /** Loading Loading @@ -122,7 +125,9 @@ import java.util.Objects; * #onDestroy()} can occur on a different thread from those made to {@link * TimeZoneProviderService}-defined service methods, so implementations must be defensive and not * assume an ordering between them, e.g. a call to {@link #onStopUpdates()} can occur after {@link * #onDestroy()} and should be handled safely. * #onDestroy()} and should be handled safely. {@link #mLock} is used to ensure that synchronous * calls like {@link #dump(FileDescriptor, PrintWriter, String[])} are safe with respect to * asynchronous behavior. * * @hide */ Loading Loading @@ -162,12 +167,26 @@ public abstract class TimeZoneProviderService extends Service { private final TimeZoneProviderServiceWrapper mWrapper = new TimeZoneProviderServiceWrapper(); /** The object used for operations that occur between the main / handler thread. */ private final Object mLock = new Object(); /** The handler used for most operations. */ private final Handler mHandler = BackgroundThread.getHandler(); /** Set by {@link #mHandler} thread. */ @GuardedBy("mLock") @Nullable private ITimeZoneProviderManager mManager; /** * The type of the last suggestion sent to the system server. Used to de-dupe suggestions client * side and avoid calling into the system server unnecessarily. {@code null} means no previous * event has been sent this cycle; this field is cleared when the service is started. */ @GuardedBy("mLock") @Nullable private TimeZoneProviderEvent mLastEventSent; @Override @NonNull public final IBinder onBind(@NonNull Intent intent) { Loading @@ -182,14 +201,21 @@ public abstract class TimeZoneProviderService extends Service { Objects.requireNonNull(suggestion); mHandler.post(() -> { synchronized (mLock) { ITimeZoneProviderManager manager = mManager; if (manager != null) { try { manager.onTimeZoneProviderSuggestion(suggestion); TimeZoneProviderEvent thisEvent = TimeZoneProviderEvent.createSuggestionEvent(suggestion); if (!thisEvent.isEquivalentTo(mLastEventSent)) { manager.onTimeZoneProviderEvent(thisEvent); mLastEventSent = thisEvent; } } catch (RemoteException | RuntimeException e) { Log.w(TAG, e); } } } }); } Loading @@ -200,14 +226,21 @@ public abstract class TimeZoneProviderService extends Service { */ public final void reportUncertain() { mHandler.post(() -> { synchronized (mLock) { ITimeZoneProviderManager manager = mManager; if (manager != null) { try { manager.onTimeZoneProviderUncertain(); TimeZoneProviderEvent thisEvent = TimeZoneProviderEvent.createUncertainEvent(); if (!thisEvent.isEquivalentTo(mLastEventSent)) { manager.onTimeZoneProviderEvent(thisEvent); mLastEventSent = thisEvent; } } catch (RemoteException | RuntimeException e) { Log.w(TAG, e); } } } }); } Loading @@ -219,22 +252,33 @@ public abstract class TimeZoneProviderService extends Service { Objects.requireNonNull(cause); mHandler.post(() -> { synchronized (mLock) { ITimeZoneProviderManager manager = mManager; if (manager != null) { try { manager.onTimeZoneProviderPermanentFailure(cause.getMessage()); String causeString = cause.getMessage(); TimeZoneProviderEvent thisEvent = TimeZoneProviderEvent.createPermanentFailureEvent(causeString); if (!thisEvent.isEquivalentTo(mLastEventSent)) { manager.onTimeZoneProviderEvent(thisEvent); mLastEventSent = thisEvent; } } catch (RemoteException | RuntimeException e) { Log.w(TAG, e); } } } }); } private void onStartUpdatesInternal(@NonNull ITimeZoneProviderManager manager, @DurationMillisLong long initializationTimeoutMillis) { synchronized (mLock) { mManager = manager; mLastEventSent = null; onStartUpdates(initializationTimeoutMillis); } } /** * Informs the provider that it should start detecting and reporting the detected time zone Loading Loading @@ -265,9 +309,11 @@ public abstract class TimeZoneProviderService extends Service { public abstract void onStartUpdates(@DurationMillisLong long initializationTimeoutMillis); private void onStopUpdatesInternal() { synchronized (mLock) { onStopUpdates(); mManager = null; } } /** * Stops the provider sending further updates. This will be called after {@link Loading @@ -275,6 +321,14 @@ public abstract class TimeZoneProviderService extends Service { */ public abstract void onStopUpdates(); /** @hide */ @Override protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { synchronized (mLock) { writer.append("mLastEventSent=" + mLastEventSent); } } private class TimeZoneProviderServiceWrapper extends ITimeZoneProvider.Stub { public void startUpdates(@NonNull ITimeZoneProviderManager manager, Loading
core/tests/coretests/src/android/service/timezone/TimeZoneProviderEventTest.java 0 → 100644 +149 −0 Original line number Diff line number Diff line /* * Copyright 2021 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 android.service.timezone; import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.junit.Test; import java.util.Arrays; import java.util.Collections; public class TimeZoneProviderEventTest { @Test public void isEquivalentToAndEquals() { TimeZoneProviderEvent fail1v1 = TimeZoneProviderEvent.createPermanentFailureEvent("one"); assertEquals(fail1v1, fail1v1); assertIsEquivalentTo(fail1v1, fail1v1); assertNotEquals(fail1v1, null); assertNotEquivalentTo(fail1v1, null); { TimeZoneProviderEvent fail1v2 = TimeZoneProviderEvent.createPermanentFailureEvent("one"); assertEquals(fail1v1, fail1v2); assertIsEquivalentTo(fail1v1, fail1v2); TimeZoneProviderEvent fail2 = TimeZoneProviderEvent.createPermanentFailureEvent("two"); assertNotEquals(fail1v1, fail2); assertIsEquivalentTo(fail1v1, fail2); } TimeZoneProviderEvent uncertain1v1 = TimeZoneProviderEvent.createUncertainEvent(); assertEquals(uncertain1v1, uncertain1v1); assertIsEquivalentTo(uncertain1v1, uncertain1v1); assertNotEquals(uncertain1v1, null); assertNotEquivalentTo(uncertain1v1, null); { TimeZoneProviderEvent uncertain1v2 = TimeZoneProviderEvent.createUncertainEvent(); assertEquals(uncertain1v1, uncertain1v2); assertIsEquivalentTo(uncertain1v1, uncertain1v2); } TimeZoneProviderSuggestion suggestion1 = new TimeZoneProviderSuggestion.Builder() .setElapsedRealtimeMillis(1111L) .setTimeZoneIds(Collections.singletonList("Europe/London")) .build(); TimeZoneProviderEvent certain1v1 = TimeZoneProviderEvent.createSuggestionEvent(suggestion1); assertEquals(certain1v1, certain1v1); assertIsEquivalentTo(certain1v1, certain1v1); assertNotEquals(certain1v1, null); assertNotEquivalentTo(certain1v1, null); { TimeZoneProviderEvent certain1v2 = TimeZoneProviderEvent.createSuggestionEvent(suggestion1); assertEquals(certain1v1, certain1v2); assertIsEquivalentTo(certain1v1, certain1v2); TimeZoneProviderSuggestion suggestion2 = new TimeZoneProviderSuggestion.Builder() .setElapsedRealtimeMillis(2222L) .setTimeZoneIds(Collections.singletonList("Europe/London")) .build(); assertNotEquals(suggestion1, suggestion2); TimeZoneProviderEvent certain2 = TimeZoneProviderEvent.createSuggestionEvent(suggestion2); assertNotEquals(certain1v1, certain2); assertIsEquivalentTo(certain1v1, certain2); TimeZoneProviderSuggestion suggestion3 = new TimeZoneProviderSuggestion.Builder() .setTimeZoneIds(Collections.singletonList("Europe/Paris")) .build(); TimeZoneProviderEvent certain3 = TimeZoneProviderEvent.createSuggestionEvent(suggestion3); assertNotEquals(certain1v1, certain3); assertNotEquivalentTo(certain1v1, certain3); } assertNotEquals(fail1v1, uncertain1v1); assertNotEquivalentTo(fail1v1, uncertain1v1); assertNotEquals(fail1v1, certain1v1); assertNotEquivalentTo(fail1v1, certain1v1); } @Test public void testParcelable_failureEvent() { TimeZoneProviderEvent event = TimeZoneProviderEvent.createPermanentFailureEvent("failure reason"); assertRoundTripParcelable(event); } @Test public void testParcelable_uncertain() { TimeZoneProviderEvent event = TimeZoneProviderEvent.createUncertainEvent(); assertRoundTripParcelable(event); } @Test public void testParcelable_suggestion() { TimeZoneProviderSuggestion suggestion = new TimeZoneProviderSuggestion.Builder() .setTimeZoneIds(Arrays.asList("Europe/London", "Europe/Paris")) .build(); TimeZoneProviderEvent event = TimeZoneProviderEvent.createSuggestionEvent(suggestion); assertRoundTripParcelable(event); } private static void assertNotEquivalentTo( TimeZoneProviderEvent one, TimeZoneProviderEvent two) { if (one == null && two == null) { fail("null arguments"); } if (one != null) { assertFalse("one=" + one + ", two=" + two, one.isEquivalentTo(two)); } if (two != null) { assertFalse("one=" + one + ", two=" + two, two.isEquivalentTo(one)); } } private static void assertIsEquivalentTo(TimeZoneProviderEvent one, TimeZoneProviderEvent two) { if (one == null || two == null) { fail("null arguments"); } assertTrue("one=" + one + ", two=" + two, one.isEquivalentTo(two)); assertTrue("one=" + one + ", two=" + two, two.isEquivalentTo(one)); } }