1 /* 2 * Copyright (C) 2012 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 android.location; 18 19 import android.annotation.NonNull; 20 import android.compat.annotation.UnsupportedAppUsage; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 import android.os.SystemClock; 24 import android.util.TimeUtils; 25 26 import com.android.internal.util.Preconditions; 27 28 import java.util.Objects; 29 30 /** 31 * Represents a geographical boundary, also known as a geofence. 32 * 33 * <p>Currently only circular geofences are supported and they do not support altitude changes. 34 * 35 * @hide 36 */ 37 public final class Geofence implements Parcelable { 38 39 private final double mLatitude; 40 private final double mLongitude; 41 private final float mRadius; 42 private long mExpirationRealtimeMs; 43 44 /** 45 * Create a circular geofence (on a flat, horizontal plane). 46 * 47 * @param latitude latitude in degrees, between -90 and +90 inclusive 48 * @param longitude longitude in degrees, between -180 and +180 inclusive 49 * @param radius radius in meters 50 * @return a new geofence 51 * @throws IllegalArgumentException if any parameters are out of range 52 */ createCircle(double latitude, double longitude, float radius, long expirationRealtimeMs)53 public static Geofence createCircle(double latitude, double longitude, float radius, 54 long expirationRealtimeMs) { 55 return new Geofence(latitude, longitude, radius, expirationRealtimeMs); 56 } 57 Geofence(double latitude, double longitude, float radius, long expirationRealtimeMs)58 Geofence(double latitude, double longitude, float radius, long expirationRealtimeMs) { 59 Preconditions.checkArgumentInRange(latitude, -90.0, 90.0, "latitude"); 60 Preconditions.checkArgumentInRange(longitude, -180.0, 180.0, "latitude"); 61 Preconditions.checkArgument(radius > 0, "invalid radius: %f", radius); 62 63 mLatitude = latitude; 64 mLongitude = longitude; 65 mRadius = radius; 66 mExpirationRealtimeMs = expirationRealtimeMs; 67 } 68 getLatitude()69 public double getLatitude() { 70 return mLatitude; 71 } 72 getLongitude()73 public double getLongitude() { 74 return mLongitude; 75 } 76 getRadius()77 public float getRadius() { 78 return mRadius; 79 } 80 isExpired()81 public boolean isExpired() { 82 return isExpired(SystemClock.elapsedRealtime()); 83 } 84 85 /** 86 * Returns true if this geofence is expired with reference to the given realtime. 87 */ isExpired(long referenceRealtimeMs)88 public boolean isExpired(long referenceRealtimeMs) { 89 return referenceRealtimeMs >= mExpirationRealtimeMs; 90 } 91 92 @UnsupportedAppUsage 93 public static final @NonNull Parcelable.Creator<Geofence> CREATOR = 94 new Parcelable.Creator<Geofence>() { 95 @Override 96 public Geofence createFromParcel(Parcel in) { 97 return new Geofence( 98 in.readDouble(), 99 in.readDouble(), 100 in.readFloat(), 101 in.readLong()); 102 } 103 104 @Override 105 public Geofence[] newArray(int size) { 106 return new Geofence[size]; 107 } 108 }; 109 110 @Override describeContents()111 public int describeContents() { 112 return 0; 113 } 114 115 @Override writeToParcel(Parcel parcel, int flags)116 public void writeToParcel(Parcel parcel, int flags) { 117 parcel.writeDouble(mLatitude); 118 parcel.writeDouble(mLongitude); 119 parcel.writeFloat(mRadius); 120 parcel.writeLong(mExpirationRealtimeMs); 121 } 122 123 @Override equals(Object o)124 public boolean equals(Object o) { 125 if (this == o) { 126 return true; 127 } 128 if (!(o instanceof Geofence)) { 129 return false; 130 } 131 Geofence geofence = (Geofence) o; 132 return Double.compare(geofence.mLatitude, mLatitude) == 0 133 && Double.compare(geofence.mLongitude, mLongitude) == 0 134 && Float.compare(geofence.mRadius, mRadius) == 0 135 && mExpirationRealtimeMs == geofence.mExpirationRealtimeMs; 136 } 137 138 @Override hashCode()139 public int hashCode() { 140 return Objects.hash(mLatitude, mLongitude, mRadius); 141 } 142 143 @Override toString()144 public String toString() { 145 StringBuilder builder = new StringBuilder(); 146 builder.append("Geofence[(").append(mLatitude).append(", ").append(mLongitude).append(")"); 147 builder.append(" ").append(mRadius).append("m"); 148 if (mExpirationRealtimeMs < Long.MAX_VALUE) { 149 if (isExpired()) { 150 builder.append(" expired"); 151 } else { 152 builder.append(" expires="); 153 TimeUtils.formatDuration(mExpirationRealtimeMs, builder); 154 } 155 } 156 builder.append("]"); 157 return builder.toString(); 158 } 159 } 160