summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/location/Geofence.java
blob: f63607a2a4ec42c27f68bf706ea1cbad197edd20 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package com.android.server.location;

import android.location.Location;

/**
 * Represents a simple circular GeoFence.
 */
public class Geofence {
    public final static int FLAG_ENTER = 0x01;
    public final static int FLAG_EXIT = 0x02;

    static final int STATE_UNKNOWN = 0;
    static final int STATE_INSIDE = 1;
    static final int STATE_OUTSIDE = 2;

    final double mLatitude;
    final double mLongitude;
    final float mRadius;
    final Location mLocation;

    int mState;  // current state
    double mDistance;  // current distance to center of fence

    public Geofence(double latitude, double longitude, float radius, Location prevLocation) {
        mState = STATE_UNKNOWN;

        mLatitude = latitude;
        mLongitude = longitude;
        mRadius = radius;

        mLocation = new Location("");
        mLocation.setLatitude(latitude);
        mLocation.setLongitude(longitude);

        if (prevLocation != null) {
            processLocation(prevLocation);
        }
    }

    /**
     * Process a new location.
     * @return FLAG_ENTER or FLAG_EXIT if the fence was crossed, 0 otherwise
     */
    public int processLocation(Location location) {
        mDistance = mLocation.distanceTo(location);

        int prevState = mState;
        //TODO: inside/outside detection could be made more rigorous
        boolean inside = mDistance <= Math.max(mRadius, location.getAccuracy());
        if (inside) {
            mState = STATE_INSIDE;
        } else {
            mState = STATE_OUTSIDE;
        }

        if (prevState != 0 && mState != prevState) {
            if (mState == STATE_INSIDE) return FLAG_ENTER;
            if (mState == STATE_OUTSIDE) return FLAG_EXIT;
        }
        return 0;
    }

    public double getDistance() {
        return mDistance;
    }

    @Override
    public String toString() {
        String state;
        switch (mState) {
            case STATE_INSIDE:
                state = "IN";
                break;
            case STATE_OUTSIDE:
                state = "OUT";
                break;
            default:
                state = "?";
        }
        return String.format("(%.4f, %.4f r=%.0f d=%.0f %s)", mLatitude, mLongitude, mRadius,
                mDistance, state);
    }
}