16fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly/*
26fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * Copyright (C) 2012 The Android Open Source Project
36fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly *
46fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * Licensed under the Apache License, Version 2.0 (the "License");
56fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * you may not use this file except in compliance with the License.
66fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * You may obtain a copy of the License at
76fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly *
86fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly *      http://www.apache.org/licenses/LICENSE-2.0
96fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly *
106fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * Unless required by applicable law or agreed to in writing, software
116fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * distributed under the License is distributed on an "AS IS" BASIS,
126fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * See the License for the specific language governing permissions and
146fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * limitations under the License.
156fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly */
166fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
176fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellypackage android.location;
186fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
196fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport android.os.Parcel;
206fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport android.os.Parcelable;
216fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
226fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly/**
234e31c4fffbc42b4c2b5dca6431cfeef9e078f5b4Nick Pelly * Represents a geographical boundary, also known as a geofence.
244e31c4fffbc42b4c2b5dca6431cfeef9e078f5b4Nick Pelly *
258761e143c987fc48d854818988cde44700c9f602Scott Main * <p>Currently only circular geofences are supported and they do not support altitude changes.
267ab7f538924371a9dd4be7a27a6ae3b4c04b301cLaurent Tu *
277ab7f538924371a9dd4be7a27a6ae3b4c04b301cLaurent Tu * @hide
286fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly */
296fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellypublic final class Geofence implements Parcelable {
306fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    /** @hide */
316fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public static final int TYPE_HORIZONTAL_CIRCLE = 1;
326fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
336fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private final int mType;
346fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private final double mLatitude;
356fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private final double mLongitude;
366fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private final float mRadius;
376fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
386fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    /**
398761e143c987fc48d854818988cde44700c9f602Scott Main     * Create a circular geofence (on a flat, horizontal plane).
404e31c4fffbc42b4c2b5dca6431cfeef9e078f5b4Nick Pelly     *
413dffb8cb691ccd3187cec193223d53b32339ed8bVictoria Lease     * @param latitude latitude in degrees, between -90 and +90 inclusive
423dffb8cb691ccd3187cec193223d53b32339ed8bVictoria Lease     * @param longitude longitude in degrees, between -180 and +180 inclusive
436fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly     * @param radius radius in meters
446fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly     * @return a new geofence
456fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly     * @throws IllegalArgumentException if any parameters are out of range
466fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly     */
476fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public static Geofence createCircle(double latitude, double longitude, float radius) {
486fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        return new Geofence(latitude, longitude, radius);
496fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
506fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
516fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private Geofence(double latitude, double longitude, float radius) {
526fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        checkRadius(radius);
536fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        checkLatLong(latitude, longitude);
546fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mType = TYPE_HORIZONTAL_CIRCLE;
556fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mLatitude = latitude;
566fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mLongitude = longitude;
576fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mRadius = radius;
586fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
596fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
606fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    /** @hide */
616fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public int getType() {
626fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        return mType;
636fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
646fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
656fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    /** @hide */
666fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public double getLatitude() {
676fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        return mLatitude;
686fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
696fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
706fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    /** @hide */
716fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public double getLongitude() {
726fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        return mLongitude;
736fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
746fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
756fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    /** @hide */
766fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public float getRadius() {
776fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        return mRadius;
786fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
796fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
806fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private static void checkRadius(float radius) {
816fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (radius <= 0) {
826fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            throw new IllegalArgumentException("invalid radius: " + radius);
836fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
846fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
856fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
866fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private static void checkLatLong(double latitude, double longitude) {
876fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (latitude > 90.0 || latitude < -90.0) {
886fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            throw new IllegalArgumentException("invalid latitude: " + latitude);
896fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
906fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (longitude > 180.0 || longitude < -180.0) {
916fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            throw new IllegalArgumentException("invalid longitude: " + longitude);
926fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
936fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
946fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
956fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private static void checkType(int type) {
966fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (type != TYPE_HORIZONTAL_CIRCLE) {
976fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            throw new IllegalArgumentException("invalid type: " + type);
986fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
996fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
1006fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1016fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public static final Parcelable.Creator<Geofence> CREATOR = new Parcelable.Creator<Geofence>() {
1026fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        @Override
1036fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        public Geofence createFromParcel(Parcel in) {
1046fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            int type = in.readInt();
1056fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            double latitude = in.readDouble();
1066fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            double longitude = in.readDouble();
1076fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            float radius = in.readFloat();
1086fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            checkType(type);
1096fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            return Geofence.createCircle(latitude, longitude, radius);
1106fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
1116fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        @Override
1126fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        public Geofence[] newArray(int size) {
1136fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            return new Geofence[size];
1146fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
1156fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    };
1166fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1176fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    @Override
1186fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public int describeContents() {
1196fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        return 0;
1206fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
1216fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1226fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    @Override
1236fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public void writeToParcel(Parcel parcel, int flags) {
1246fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        parcel.writeInt(mType);
1256fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        parcel.writeDouble(mLatitude);
1266fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        parcel.writeDouble(mLongitude);
1276fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        parcel.writeFloat(mRadius);
1286fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
1296fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1306fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private static String typeToString(int type) {
1316fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        switch (type) {
1326fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            case TYPE_HORIZONTAL_CIRCLE:
1336fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                return "CIRCLE";
1346fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            default:
1356fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                checkType(type);
1366fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                return null;
1376fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
1386fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
1396fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1406fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    @Override
1416fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public String toString() {
1426fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        return String.format("Geofence[%s %.6f, %.6f %.0fm]",
1436fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                typeToString(mType), mLatitude, mLongitude, mRadius);
1446fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
1456fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1466fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    @Override
1476fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public int hashCode() {
1486fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        final int prime = 31;
1496fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        int result = 1;
1506fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        long temp;
1516fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        temp = Double.doubleToLongBits(mLatitude);
1526fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        result = prime * result + (int) (temp ^ (temp >>> 32));
1536fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        temp = Double.doubleToLongBits(mLongitude);
1546fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        result = prime * result + (int) (temp ^ (temp >>> 32));
1556fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        result = prime * result + Float.floatToIntBits(mRadius);
1566fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        result = prime * result + mType;
1576fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        return result;
1586fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
1596fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1604e31c4fffbc42b4c2b5dca6431cfeef9e078f5b4Nick Pelly    /**
1614e31c4fffbc42b4c2b5dca6431cfeef9e078f5b4Nick Pelly     * Two geofences are equal if they have identical properties.
1624e31c4fffbc42b4c2b5dca6431cfeef9e078f5b4Nick Pelly     */
1636fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    @Override
1646fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public boolean equals(Object obj) {
1656fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (this == obj)
1666fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            return true;
1676fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (obj == null)
1686fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            return false;
1696fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (!(obj instanceof Geofence))
1706fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            return false;
1716fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        Geofence other = (Geofence) obj;
1726fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (mRadius != other.mRadius)
1736fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            return false;
1746fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (mLatitude != other.mLatitude)
1756fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            return false;
1766fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (mLongitude != other.mLongitude)
1776fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            return false;
1786fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (mType != other.mType)
1796fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            return false;
1806fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        return true;
1816fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
1826fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly}
183