1/*
2 * Copyright (C) 2014 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
17package com.android.location.provider;
18
19import com.android.internal.util.Preconditions;
20
21import android.hardware.location.IActivityRecognitionHardware;
22import android.hardware.location.IActivityRecognitionHardwareSink;
23import android.os.RemoteException;
24
25import java.util.ArrayList;
26import java.util.Collection;
27import java.util.HashSet;
28
29/**
30 * A class that exposes {@link IActivityRecognitionHardware} functionality to unbundled services.
31 */
32public final class ActivityRecognitionProvider {
33    private final IActivityRecognitionHardware mService;
34    private final HashSet<Sink> mSinkSet = new HashSet<Sink>();
35    private final SinkTransport mSinkTransport = new SinkTransport();
36
37    // the following constants must remain in sync with activity_recognition.h
38
39    public static final String ACTIVITY_IN_VEHICLE = "android.activity_recognition.in_vehicle";
40    public static final String ACTIVITY_ON_BICYCLE = "android.activity_recognition.on_bicycle";
41    public static final String ACTIVITY_WALKING = "android.activity_recognition.walking";
42    public static final String ACTIVITY_RUNNING = "android.activity_recognition.running";
43    public static final String ACTIVITY_STILL = "android.activity_recognition.still";
44    public static final String ACTIVITY_TILTING = "android.activity_recognition.tilting";
45
46    public static final int EVENT_TYPE_FLUSH_COMPLETE = 0;
47    public static final int EVENT_TYPE_ENTER = 1;
48    public static final int EVENT_TYPE_EXIT = 2;
49
50    // end constants activity_recognition.h
51
52    /**
53     * Used to receive Activity-Recognition events.
54     */
55    public interface Sink {
56        void onActivityChanged(ActivityChangedEvent event);
57    }
58
59    public ActivityRecognitionProvider(IActivityRecognitionHardware service)
60            throws RemoteException {
61        Preconditions.checkNotNull(service);
62        mService = service;
63        mService.registerSink(mSinkTransport);
64    }
65
66    public String[] getSupportedActivities() throws RemoteException {
67        return mService.getSupportedActivities();
68    }
69
70    public boolean isActivitySupported(String activity) throws RemoteException {
71        return mService.isActivitySupported(activity);
72    }
73
74    public void registerSink(Sink sink) {
75        Preconditions.checkNotNull(sink);
76        synchronized (mSinkSet) {
77            mSinkSet.add(sink);
78        }
79    }
80
81    // TODO: if this functionality is exposed to 3rd party developers, handle unregistration (here
82    // and in the service) of all sinks while failing to disable all events
83    public void unregisterSink(Sink sink) {
84        Preconditions.checkNotNull(sink);
85        synchronized (mSinkSet) {
86            mSinkSet.remove(sink);
87        }
88    }
89
90    public boolean enableActivityEvent(String activity, int eventType, long reportLatencyNs)
91            throws RemoteException {
92        return mService.enableActivityEvent(activity, eventType, reportLatencyNs);
93    }
94
95    public boolean disableActivityEvent(String activity, int eventType) throws RemoteException {
96        return mService.disableActivityEvent(activity, eventType);
97    }
98
99    public boolean flush() throws RemoteException {
100        return mService.flush();
101    }
102
103    private final class SinkTransport extends IActivityRecognitionHardwareSink.Stub {
104        @Override
105        public void onActivityChanged(
106                android.hardware.location.ActivityChangedEvent activityChangedEvent) {
107            Collection<Sink> sinks;
108            synchronized (mSinkSet) {
109                if (mSinkSet.isEmpty()) {
110                    return;
111                }
112
113                sinks = new ArrayList<Sink>(mSinkSet);
114            }
115
116            // translate the event from platform internal and GmsCore types
117            ArrayList<ActivityRecognitionEvent> gmsEvents =
118                    new ArrayList<ActivityRecognitionEvent>();
119            for (android.hardware.location.ActivityRecognitionEvent event
120                    : activityChangedEvent.getActivityRecognitionEvents()) {
121                ActivityRecognitionEvent gmsEvent = new ActivityRecognitionEvent(
122                        event.getActivity(),
123                        event.getEventType(),
124                        event.getTimestampNs());
125                gmsEvents.add(gmsEvent);
126            }
127            ActivityChangedEvent gmsEvent = new ActivityChangedEvent(gmsEvents);
128
129            for (Sink sink : sinks) {
130                sink.onActivityChanged(gmsEvent);
131            }
132        }
133    }
134}
135