Skip to content

Most visited

Recently visited

navigation
BatchStepSensor / src / com.example.android.batchstepsensor /

BatchStepSensorFragment.java

1
/*
2
* Copyright 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
 
17
package com.example.android.batchstepsensor;
18
 
19
import android.app.Activity;
20
import android.content.pm.PackageManager;
21
import android.hardware.Sensor;
22
import android.hardware.SensorEvent;
23
import android.hardware.SensorEventListener;
24
import android.hardware.SensorManager;
25
import android.os.Bundle;
26
import android.support.v4.app.Fragment;
27
 
28
import com.example.android.common.logger.Log;
29
import com.example.android.batchstepsensor.cardstream.Card;
30
import com.example.android.batchstepsensor.cardstream.CardStream;
31
import com.example.android.batchstepsensor.cardstream.CardStreamFragment;
32
import com.example.android.batchstepsensor.cardstream.OnCardClickListener;
33
 
34
public class BatchStepSensorFragment extends Fragment implements OnCardClickListener {
35
 
36
    public static final String TAG = "StepSensorSample";
37
    // Cards
38
    private CardStreamFragment mCards = null;
39
 
40
    // Card tags
41
    public static final String CARD_INTRO = "intro";
42
    public static final String CARD_REGISTER_DETECTOR = "register_detector";
43
    public static final String CARD_REGISTER_COUNTER = "register_counter";
44
    public static final String CARD_BATCHING_DESCRIPTION = "register_batching_description";
45
    public static final String CARD_COUNTING = "counting";
46
    public static final String CARD_EXPLANATION = "explanation";
47
    public static final String CARD_NOBATCHSUPPORT = "error";
48
 
49
    // Actions from REGISTER cards
50
    public static final int ACTION_REGISTER_DETECT_NOBATCHING = 10;
51
    public static final int ACTION_REGISTER_DETECT_BATCHING_5s = 11;
52
    public static final int ACTION_REGISTER_DETECT_BATCHING_10s = 12;
53
    public static final int ACTION_REGISTER_COUNT_NOBATCHING = 21;
54
    public static final int ACTION_REGISTER_COUNT_BATCHING_5s = 22;
55
    public static final int ACTION_REGISTER_COUNT_BATCHING_10s = 23;
56
    // Action from COUNTING card
57
    public static final int ACTION_UNREGISTER = 1;
58
    // Actions from description cards
59
    private static final int ACTION_BATCHING_DESCRIPTION_DISMISS = 2;
60
    private static final int ACTION_EXPLANATION_DISMISS = 3;
61
 
62
    // State of application, used to register for sensors when app is restored
63
    public static final int STATE_OTHER = 0;
64
    public static final int STATE_COUNTER = 1;
65
    public static final int STATE_DETECTOR = 2;
66
 
67
    // Bundle tags used to store data when restoring application state
68
    private static final String BUNDLE_STATE = "state";
69
    private static final String BUNDLE_LATENCY = "latency";
70
    private static final String BUNDLE_STEPS = "steps";
71
 
72
    // max batch latency is specified in microseconds
73
    private static final int BATCH_LATENCY_0 = 0; // no batching
74
    private static final int BATCH_LATENCY_10s = 10000000;
75
    private static final int BATCH_LATENCY_5s = 5000000;
76
 
77
    /*
78
    For illustration we keep track of the last few events and show their delay from when the
79
    event occurred until it was received by the event listener.
80
    These variables keep track of the list of timestamps and the number of events.
81
     */
82
    // Number of events to keep in queue and display on card
83
    private static final int EVENT_QUEUE_LENGTH = 10;
84
    // List of timestamps when sensor events occurred
85
    private float[] mEventDelays = new float[EVENT_QUEUE_LENGTH];
86
 
87
    // number of events in event list
88
    private int mEventLength = 0;
89
    // pointer to next entry in sensor event list
90
    private int mEventData = 0;
91
 
92
    // Steps counted in current session
93
    private int mSteps = 0;
94
    // Value of the step counter sensor when the listener was registered.
95
    // (Total steps are calculated from this value.)
96
    private int mCounterSteps = 0;
97
    // Steps counted by the step counter previously. Used to keep counter consistent across rotation
98
    // changes
99
    private int mPreviousCounterSteps = 0;
100
    // State of the app (STATE_OTHER, STATE_COUNTER or STATE_DETECTOR)
101
    private int mState = STATE_OTHER;
102
    // When a listener is registered, the batch sensor delay in microseconds
103
    private int mMaxDelay = 0;
104
 
105
    @Override
106
    public void onResume() {
107
        super.onResume();
108
 
109
        CardStreamFragment stream = getCardStream();
110
        if (stream.getVisibleCardCount() < 1) {
111
            // No cards are visible, started for the first time
112
            // Prepare all cards and show the intro card.
113
            initialiseCards();
114
            showIntroCard();
115
            // Show the registration card if the hardware is supported, show an error otherwise
116
            if (isKitkatWithStepSensor()) {
117
                showRegisterCard();
118
            } else {
119
                showErrorCard();
120
            }
121
        }
122
    }
123
 
124
    @Override
125
    public void onPause() {
126
        super.onPause();
128
        // Unregister the listener when the application is paused
129
        unregisterListeners();
131
    }
132
 
133
    /**
134
     * Returns true if this device is supported. It needs to be running Android KitKat (4.4) or
135
     * higher and has a step counter and step detector sensor.
136
     * This check is useful when an app provides an alternative implementation or different
137
     * functionality if the step sensors are not available or this code runs on a platform version
138
     * below Android KitKat. If this functionality is required, then the minSDK parameter should
139
     * be specified appropriately in the AndroidManifest.
140
     *
141
     * @return True iff the device can run this sample
142
     */
143
    private boolean isKitkatWithStepSensor() {
145
        // Require at least Android KitKat
146
        int currentApiVersion = android.os.Build.VERSION.SDK_INT;
147
        // Check that the device supports the step counter and detector sensors
148
        PackageManager packageManager = getActivity().getPackageManager();
149
        return currentApiVersion >= android.os.Build.VERSION_CODES.KITKAT
150
                && packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_COUNTER)
151
                && packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_DETECTOR);
153
    }
154
 
155
    /**
156
     * Handles a click on a card action.
157
     * Registers a SensorEventListener (see {@link #registerEventListener(int, int)}) with the
158
     * selected delay, dismisses cards and unregisters the listener
159
     * (see {@link #unregisterListeners()}).
160
     * Actions are defined when a card is created.
161
     *
162
     * @param cardActionId
163
     * @param cardTag
164
     */
165
    @Override
166
    public void onCardClick(int cardActionId, String cardTag) {
167
 
168
        switch (cardActionId) {
170
            // Register Step Counter card
171
            case ACTION_REGISTER_COUNT_NOBATCHING:
172
                registerEventListener(BATCH_LATENCY_0, Sensor.TYPE_STEP_COUNTER);
173
                break;
174
            case ACTION_REGISTER_COUNT_BATCHING_5s:
175
                registerEventListener(BATCH_LATENCY_5s, Sensor.TYPE_STEP_COUNTER);
176
                break;
177
            case ACTION_REGISTER_COUNT_BATCHING_10s:
178
                registerEventListener(BATCH_LATENCY_10s, Sensor.TYPE_STEP_COUNTER);
179
                break;
180
 
181
            // Register Step Detector card
182
            case ACTION_REGISTER_DETECT_NOBATCHING:
183
                registerEventListener(BATCH_LATENCY_0, Sensor.TYPE_STEP_DETECTOR);
184
                break;
185
            case ACTION_REGISTER_DETECT_BATCHING_5s:
186
                registerEventListener(BATCH_LATENCY_5s, Sensor.TYPE_STEP_DETECTOR);
187
                break;
188
            case ACTION_REGISTER_DETECT_BATCHING_10s:
189
                registerEventListener(BATCH_LATENCY_10s, Sensor.TYPE_STEP_DETECTOR);
190
                break;
191
 
192
            // Unregister card
193
            case ACTION_UNREGISTER:
194
                showRegisterCard();
195
                unregisterListeners();
196
                // reset the application state when explicitly unregistered
197
                mState = STATE_OTHER;
198
                break;
200
            // Explanation cards
201
            case ACTION_BATCHING_DESCRIPTION_DISMISS:
202
                // permanently remove the batch description card, it will not be shown again
203
                getCardStream().removeCard(CARD_BATCHING_DESCRIPTION);
204
                break;
205
            case ACTION_EXPLANATION_DISMISS:
206
                // permanently remove the explanation card, it will not be shown again
207
                getCardStream().removeCard(CARD_EXPLANATION);
208
        }
209
 
210
        // For register cards, display the counting card
211
        if (cardTag.equals(CARD_REGISTER_COUNTER) || cardTag.equals(CARD_REGISTER_DETECTOR)) {
212
            showCountingCards();
213
        }
214
    }
215
 
216
    /**
217
     * Register a {@link android.hardware.SensorEventListener} for the sensor and max batch delay.
218
     * The maximum batch delay specifies the maximum duration in microseconds for which subsequent
219
     * sensor events can be temporarily stored by the sensor before they are delivered to the
220
     * registered SensorEventListener. A larger delay allows the system to handle sensor events more
221
     * efficiently, allowing the system to switch to a lower power state while the sensor is
222
     * capturing events. Once the max delay is reached, all stored events are delivered to the
223
     * registered listener. Note that this value only specifies the maximum delay, the listener may
224
     * receive events quicker. A delay of 0 disables batch mode and registers the listener in
225
     * continuous mode.
226
     * The optimium batch delay depends on the application. For example, a delay of 5 seconds or
227
     * higher may be appropriate for an  application that does not update the UI in real time.
228
     *
229
     * @param maxdelay
230
     * @param sensorType
231
     */
232
    private void registerEventListener(int maxdelay, int sensorType) {
234
 
235
        // Keep track of state so that the correct sensor type and batch delay can be set up when
236
        // the app is restored (for example on screen rotation).
237
        mMaxDelay = maxdelay;
238
        if (sensorType == Sensor.TYPE_STEP_COUNTER) {
239
            mState = STATE_COUNTER;
240
            /*
241
            Reset the initial step counter value, the first event received by the event listener is
242
            stored in mCounterSteps and used to calculate the total number of steps taken.
243
             */
244
            mCounterSteps = 0;
245
            Log.i(TAG, "Event listener for step counter sensor registered with a max delay of "
246
                    + mMaxDelay);
247
        } else {
248
            mState = STATE_DETECTOR;
249
            Log.i(TAG, "Event listener for step detector sensor registered with a max delay of "
250
                    + mMaxDelay);
251
        }
252
 
253
        // Get the default sensor for the sensor type from the SenorManager
254
        SensorManager sensorManager =
255
                (SensorManager) getActivity().getSystemService(Activity.SENSOR_SERVICE);
256
        // sensorType is either Sensor.TYPE_STEP_COUNTER or Sensor.TYPE_STEP_DETECTOR
257
        Sensor sensor = sensorManager.getDefaultSensor(sensorType);
258
 
259
        // Register the listener for this sensor in batch mode.
260
        // If the max delay is 0, events will be delivered in continuous mode without batching.
261
        final boolean batchMode = sensorManager.registerListener(
262
                mListener, sensor, SensorManager.SENSOR_DELAY_NORMAL, maxdelay);
263
 
264
        if (!batchMode) {
265
            // Batch mode could not be enabled, show a warning message and switch to continuous mode
266
            getCardStream().getCard(CARD_NOBATCHSUPPORT)
267
                    .setDescription(getString(R.string.warning_nobatching));
268
            getCardStream().showCard(CARD_NOBATCHSUPPORT);
269
            Log.w(TAG, "Could not register sensor listener in batch mode, " +
270
                    "falling back to continuous mode.");
271
        }
272
 
273
        if (maxdelay > 0 && batchMode) {
274
            // Batch mode was enabled successfully, show a description card
275
            getCardStream().showCard(CARD_BATCHING_DESCRIPTION);
276
        }
277
 
278
        // Show the explanation card
279
        getCardStream().showCard(CARD_EXPLANATION);
280
 
282
 
283
    }
284
 
285
    /**
286
     * Unregisters the sensor listener if it is registered.
287
     */
288
    private void unregisterListeners() {
290
        SensorManager sensorManager =
291
                (SensorManager) getActivity().getSystemService(Activity.SENSOR_SERVICE);
292
        sensorManager.unregisterListener(mListener);
293
        Log.i(TAG, "Sensor listener unregistered.");
294
 
296
    }
297