├── .google
└── packaging.yaml
├── Application
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── example
│ │ └── android
│ │ ├── batchstepsensor
│ │ ├── BatchStepSensorFragment.java
│ │ ├── MainActivity.java
│ │ └── cardstream
│ │ │ ├── Card.java
│ │ │ ├── CardActionButton.java
│ │ │ ├── CardLayout.java
│ │ │ ├── CardStream.java
│ │ │ ├── CardStreamAnimator.java
│ │ │ ├── CardStreamFragment.java
│ │ │ ├── CardStreamLinearLayout.java
│ │ │ ├── CardStreamState.java
│ │ │ ├── DefaultCardStreamAnimator.java
│ │ │ ├── OnCardClickListener.java
│ │ │ └── StreamRetentionFragment.java
│ │ └── common
│ │ ├── activities
│ │ └── SampleActivityBase.java
│ │ └── logger
│ │ ├── Log.java
│ │ ├── LogFragment.java
│ │ ├── LogNode.java
│ │ ├── LogView.java
│ │ ├── LogWrapper.java
│ │ └── MessageOnlyLogFilter.java
│ └── res
│ ├── drawable-hdpi
│ ├── ic_action_cancel.png
│ ├── ic_launcher.png
│ └── tile.9.png
│ ├── drawable-mdpi
│ ├── ic_action_cancel.png
│ └── ic_launcher.png
│ ├── drawable-v21
│ ├── card_action_bg.xml
│ ├── card_action_bg_negative.xml
│ └── card_action_bg_positive.xml
│ ├── drawable-xhdpi
│ ├── card_bg.9.png
│ ├── ic_cardaction_negative.png
│ ├── ic_cardaction_negative_pressed.png
│ ├── ic_cardaction_neutral.png
│ ├── ic_cardaction_neutral_pressed.png
│ ├── ic_cardaction_positive.png
│ ├── ic_cardaction_positive_pressed.png
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ ├── ic_action_cancel.png
│ └── ic_launcher.png
│ ├── drawable
│ ├── card_action_bg.xml
│ ├── card_action_bg_negative.xml
│ ├── card_action_bg_positive.xml
│ ├── card_action_icon_negative.xml
│ ├── card_action_icon_neutral.xml
│ ├── card_action_icon_positive.xml
│ ├── card_action_text.xml
│ ├── card_action_text_negative.xml
│ ├── card_action_text_positive.xml
│ ├── card_overlay_focused.xml
│ └── card_separator.xml
│ ├── layout
│ ├── activity_main.xml
│ ├── card.xml
│ ├── card_button_negative.xml
│ ├── card_button_neutral.xml
│ ├── card_button_positive.xml
│ ├── card_button_seperator.xml
│ ├── card_progress.xml
│ └── cardstream.xml
│ ├── values-sw600dp
│ ├── template-dimens.xml
│ └── template-styles.xml
│ ├── values-sw720dp-land
│ └── dimens.xml
│ ├── values-v11
│ ├── styles.xml
│ └── template-styles.xml
│ ├── values-v14
│ └── styles.xml
│ ├── values-v16
│ └── styles.xml
│ ├── values-v21
│ ├── base-colors.xml
│ └── base-template-styles.xml
│ └── values
│ ├── attrs.xml
│ ├── base-strings.xml
│ ├── color.xml
│ ├── dimens.xml
│ ├── ids.xml
│ ├── strings.xml
│ ├── styles.xml
│ ├── template-dimens.xml
│ └── template-styles.xml
├── CONTRIB.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── packaging.yaml
├── screenshots
├── big_icon.png
├── screenshot1.png
├── screenshot2.png
├── screenshot3.png
├── screenshot4.png
└── screenshot5.png
└── settings.gradle
/.google/packaging.yaml:
--------------------------------------------------------------------------------
1 |
2 | # GOOGLE SAMPLE PACKAGING DATA
3 | #
4 | # This file is used by Google as part of our samples packaging process.
5 | # End users may safely ignore this file. It has no relevance to other systems.
6 | ---
7 | status: PUBLISHED
8 | technologies: [Android]
9 | categories: [Sensors]
10 | languages: [Java]
11 | solutions: [Mobile]
12 | github: android-BatchStepSensor
13 | level: ADVANCED
14 | icon: screenshots/big_icon.png
15 | apiRefs:
16 | - android:android.hardware.Sensor
17 | - android:android.hardware.SensorEvent
18 | - android:android.hardware.SensorEventListener
19 | - android:android.hardware.SensorManager
20 | license: apache2
21 |
--------------------------------------------------------------------------------
/Application/build.gradle:
--------------------------------------------------------------------------------
1 |
2 | buildscript {
3 | repositories {
4 | jcenter()
5 | google()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.0.1'
10 | }
11 | }
12 |
13 | apply plugin: 'com.android.application'
14 |
15 | repositories {
16 | jcenter()
17 | google()
18 | }
19 |
20 | dependencies {
21 | compile "com.android.support:support-v4:27.0.2"
22 | compile "com.android.support:support-v13:27.0.2"
23 | compile "com.android.support:cardview-v7:27.0.2"
24 | compile "com.android.support:appcompat-v7:27.0.2"
25 | }
26 |
27 | // The sample build uses multiple directories to
28 | // keep boilerplate and common code separate from
29 | // the main sample code.
30 | List dirs = [
31 | 'main', // main sample code; look here for the interesting stuff.
32 | 'common', // components that are reused by multiple samples
33 | 'template'] // boilerplate code that is generated by the sample template process
34 |
35 | android {
36 | compileSdkVersion 27
37 |
38 | buildToolsVersion "27.0.2"
39 |
40 | defaultConfig {
41 | minSdkVersion 19
42 | targetSdkVersion 27
43 | }
44 |
45 | compileOptions {
46 | sourceCompatibility JavaVersion.VERSION_1_7
47 | targetCompatibility JavaVersion.VERSION_1_7
48 | }
49 |
50 | sourceSets {
51 | main {
52 | dirs.each { dir ->
53 | java.srcDirs "src/${dir}/java"
54 | res.srcDirs "src/${dir}/res"
55 | }
56 | }
57 | androidTest.setRoot('tests')
58 | androidTest.java.srcDirs = ['tests/src']
59 |
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/Application/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
32 |
33 |
34 |
35 |
36 |
40 |
41 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Application/src/main/java/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();
127 | // BEGIN_INCLUDE(onpause)
128 | // Unregister the listener when the application is paused
129 | unregisterListeners();
130 | // END_INCLUDE(onpause)
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() {
144 | // BEGIN_INCLUDE(iskitkatsensor)
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);
152 | // END_INCLUDE(iskitkatsensor)
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) {
169 | // BEGIN_INCLUDE(onclick)
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;
199 | // END_INCLUDE(onclick)
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) {
233 | // BEGIN_INCLUDE(register)
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 |
281 | // END_INCLUDE(register)
282 |
283 | }
284 |
285 | /**
286 | * Unregisters the sensor listener if it is registered.
287 | */
288 | private void unregisterListeners() {
289 | // BEGIN_INCLUDE(unregister)
290 | SensorManager sensorManager =
291 | (SensorManager) getActivity().getSystemService(Activity.SENSOR_SERVICE);
292 | sensorManager.unregisterListener(mListener);
293 | Log.i(TAG, "Sensor listener unregistered.");
294 |
295 | // END_INCLUDE(unregister)
296 | }
297 |
298 | /**
299 | * Resets the step counter by clearing all counting variables and lists.
300 | */
301 | private void resetCounter() {
302 | // BEGIN_INCLUDE(reset)
303 | mSteps = 0;
304 | mCounterSteps = 0;
305 | mEventLength = 0;
306 | mEventDelays = new float[EVENT_QUEUE_LENGTH];
307 | mPreviousCounterSteps = 0;
308 | // END_INCLUDE(reset)
309 | }
310 |
311 |
312 | /**
313 | * Listener that handles step sensor events for step detector and step counter sensors.
314 | */
315 | private final SensorEventListener mListener = new SensorEventListener() {
316 | @Override
317 | public void onSensorChanged(SensorEvent event) {
318 | // BEGIN_INCLUDE(sensorevent)
319 | // store the delay of this event
320 | recordDelay(event);
321 | final String delayString = getDelayString();
322 |
323 | if (event.sensor.getType() == Sensor.TYPE_STEP_DETECTOR) {
324 | // A step detector event is received for each step.
325 | // This means we need to count steps ourselves
326 |
327 | mSteps += event.values.length;
328 |
329 | // Update the card with the latest step count
330 | getCardStream().getCard(CARD_COUNTING)
331 | .setTitle(getString(R.string.counting_title, mSteps))
332 | .setDescription(getString(R.string.counting_description,
333 | getString(R.string.sensor_detector), mMaxDelay, delayString));
334 |
335 | Log.i(TAG,
336 | "New step detected by STEP_DETECTOR sensor. Total step count: " + mSteps);
337 |
338 | } else if (event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) {
339 |
340 | /*
341 | A step counter event contains the total number of steps since the listener
342 | was first registered. We need to keep track of this initial value to calculate the
343 | number of steps taken, as the first value a listener receives is undefined.
344 | */
345 | if (mCounterSteps < 1) {
346 | // initial value
347 | mCounterSteps = (int) event.values[0];
348 | }
349 |
350 | // Calculate steps taken based on first counter value received.
351 | mSteps = (int) event.values[0] - mCounterSteps;
352 |
353 | // Add the number of steps previously taken, otherwise the counter would start at 0.
354 | // This is needed to keep the counter consistent across rotation changes.
355 | mSteps = mSteps + mPreviousCounterSteps;
356 |
357 | // Update the card with the latest step count
358 | getCardStream().getCard(CARD_COUNTING)
359 | .setTitle(getString(R.string.counting_title, mSteps))
360 | .setDescription(getString(R.string.counting_description,
361 | getString(R.string.sensor_counter), mMaxDelay, delayString));
362 | Log.i(TAG, "New step detected by STEP_COUNTER sensor. Total step count: " + mSteps);
363 | // END_INCLUDE(sensorevent)
364 | }
365 | }
366 |
367 | @Override
368 | public void onAccuracyChanged(Sensor sensor, int accuracy) {
369 |
370 | }
371 | };
372 |
373 | /**
374 | * Records the delay for the event.
375 | *
376 | * @param event
377 | */
378 | private void recordDelay(SensorEvent event) {
379 | // Calculate the delay from when event was recorded until it was received here in ms
380 | // Event timestamp is recorded in us accuracy, but ms accuracy is sufficient here
381 | mEventDelays[mEventData] = System.currentTimeMillis() - (event.timestamp / 1000000L);
382 |
383 | // Increment length counter
384 | mEventLength = Math.min(EVENT_QUEUE_LENGTH, mEventLength + 1);
385 | // Move pointer to the next (oldest) location
386 | mEventData = (mEventData + 1) % EVENT_QUEUE_LENGTH;
387 | }
388 |
389 | private final StringBuffer mDelayStringBuffer = new StringBuffer();
390 |
391 | /**
392 | * Returns a string describing the sensor delays recorded in
393 | * {@link #recordDelay(android.hardware.SensorEvent)}.
394 | *
395 | * @return
396 | */
397 | private String getDelayString() {
398 | // Empty the StringBuffer
399 | mDelayStringBuffer.setLength(0);
400 |
401 | // Loop over all recorded delays and append them to the buffer as a decimal
402 | for (int i = 0; i < mEventLength; i++) {
403 | if (i > 0) {
404 | mDelayStringBuffer.append(", ");
405 | }
406 | final int index = (mEventData + i) % EVENT_QUEUE_LENGTH;
407 | final float delay = mEventDelays[index] / 1000f; // convert delay from ms into s
408 | mDelayStringBuffer.append(String.format("%1.1f", delay));
409 | }
410 |
411 | return mDelayStringBuffer.toString();
412 | }
413 |
414 | /**
415 | * Records the state of the application into the {@link android.os.Bundle}.
416 | *
417 | * @param outState
418 | */
419 | @Override
420 | public void onSaveInstanceState(Bundle outState) {
421 | // BEGIN_INCLUDE(saveinstance)
422 | super.onSaveInstanceState(outState);
423 | // Store all variables required to restore the state of the application
424 | outState.putInt(BUNDLE_LATENCY, mMaxDelay);
425 | outState.putInt(BUNDLE_STATE, mState);
426 | outState.putInt(BUNDLE_STEPS, mSteps);
427 | // END_INCLUDE(saveinstance)
428 | }
429 |
430 | @Override
431 | public void onActivityCreated(Bundle savedInstanceState) {
432 | super.onActivityCreated(savedInstanceState);
433 | // BEGIN_INCLUDE(restore)
434 | // Fragment is being restored, reinitialise its state with data from the bundle
435 | if (savedInstanceState != null) {
436 | resetCounter();
437 | mSteps = savedInstanceState.getInt(BUNDLE_STEPS);
438 | mState = savedInstanceState.getInt(BUNDLE_STATE);
439 | mMaxDelay = savedInstanceState.getInt(BUNDLE_LATENCY);
440 |
441 | // Register listeners again if in detector or counter states with restored delay
442 | if (mState == STATE_DETECTOR) {
443 | registerEventListener(mMaxDelay, Sensor.TYPE_STEP_DETECTOR);
444 | } else if (mState == STATE_COUNTER) {
445 | // store the previous number of steps to keep step counter count consistent
446 | mPreviousCounterSteps = mSteps;
447 | registerEventListener(mMaxDelay, Sensor.TYPE_STEP_COUNTER);
448 | }
449 | }
450 | // END_INCLUDE(restore)
451 | }
452 |
453 | /**
454 | * Hides the registration cards, reset the counter and show the step counting card.
455 | */
456 | private void showCountingCards() {
457 | // Hide the registration cards
458 | getCardStream().hideCard(CARD_REGISTER_DETECTOR);
459 | getCardStream().hideCard(CARD_REGISTER_COUNTER);
460 |
461 | // Show the explanation card if it has not been dismissed
462 | getCardStream().showCard(CARD_EXPLANATION);
463 |
464 | // Reset the step counter, then show the step counting card
465 | resetCounter();
466 |
467 | // Set the inital text for the step counting card before a step is recorded
468 | String sensor = "-";
469 | if (mState == STATE_COUNTER) {
470 | sensor = getString(R.string.sensor_counter);
471 | } else if (mState == STATE_DETECTOR) {
472 | sensor = getString(R.string.sensor_detector);
473 | }
474 | // Set initial text
475 | getCardStream().getCard(CARD_COUNTING)
476 | .setTitle(getString(R.string.counting_title, 0))
477 | .setDescription(getString(R.string.counting_description, sensor, mMaxDelay, "-"));
478 |
479 | // Show the counting card and make it undismissable
480 | getCardStream().showCard(CARD_COUNTING, false);
481 |
482 | }
483 |
484 | /**
485 | * Show the introduction card
486 | */
487 | private void showIntroCard() {
488 | Card c = new Card.Builder(this, CARD_INTRO)
489 | .setTitle(getString(R.string.intro_title))
490 | .setDescription(getString(R.string.intro_message))
491 | .build(getActivity());
492 | getCardStream().addCard(c, true);
493 | }
494 |
495 | /**
496 | * Show two registration cards, one for the step detector and counter sensors.
497 | */
498 | private void showRegisterCard() {
499 | // Hide the counting and explanation cards
500 | getCardStream().hideCard(CARD_BATCHING_DESCRIPTION);
501 | getCardStream().hideCard(CARD_EXPLANATION);
502 | getCardStream().hideCard(CARD_COUNTING);
503 |
504 | // Show two undismissable registration cards, one for each step sensor
505 | getCardStream().showCard(CARD_REGISTER_DETECTOR, false);
506 | getCardStream().showCard(CARD_REGISTER_COUNTER, false);
507 | }
508 |
509 | /**
510 | * Show the error card.
511 | */
512 | private void showErrorCard() {
513 | getCardStream().showCard(CARD_NOBATCHSUPPORT, false);
514 | }
515 |
516 | /**
517 | * Initialise Cards.
518 | */
519 | private void initialiseCards() {
520 | // Step counting
521 | Card c = new Card.Builder(this, CARD_COUNTING)
522 | .setTitle("Steps")
523 | .setDescription("")
524 | .addAction("Unregister Listener", ACTION_UNREGISTER, Card.ACTION_NEGATIVE)
525 | .build(getActivity());
526 | getCardStream().addCard(c);
527 |
528 | // Register step detector listener
529 | c = new Card.Builder(this, CARD_REGISTER_DETECTOR)
530 | .setTitle(getString(R.string.register_detector_title))
531 | .setDescription(getString(R.string.register_detector_description))
532 | .addAction(getString(R.string.register_0),
533 | ACTION_REGISTER_DETECT_NOBATCHING, Card.ACTION_NEUTRAL)
534 | .addAction(getString(R.string.register_5),
535 | ACTION_REGISTER_DETECT_BATCHING_5s, Card.ACTION_NEUTRAL)
536 | .addAction(getString(R.string.register_10),
537 | ACTION_REGISTER_DETECT_BATCHING_10s, Card.ACTION_NEUTRAL)
538 | .build(getActivity());
539 | getCardStream().addCard(c);
540 |
541 | // Register step counter listener
542 | c = new Card.Builder(this, CARD_REGISTER_COUNTER)
543 | .setTitle(getString(R.string.register_counter_title))
544 | .setDescription(getString(R.string.register_counter_description))
545 | .addAction(getString(R.string.register_0),
546 | ACTION_REGISTER_COUNT_NOBATCHING, Card.ACTION_NEUTRAL)
547 | .addAction(getString(R.string.register_5),
548 | ACTION_REGISTER_COUNT_BATCHING_5s, Card.ACTION_NEUTRAL)
549 | .addAction(getString(R.string.register_10),
550 | ACTION_REGISTER_COUNT_BATCHING_10s, Card.ACTION_NEUTRAL)
551 | .build(getActivity());
552 | getCardStream().addCard(c);
553 |
554 |
555 | // Batching description
556 | c = new Card.Builder(this, CARD_BATCHING_DESCRIPTION)
557 | .setTitle(getString(R.string.batching_queue_title))
558 | .setDescription(getString(R.string.batching_queue_description))
559 | .addAction(getString(R.string.action_notagain),
560 | ACTION_BATCHING_DESCRIPTION_DISMISS, Card.ACTION_POSITIVE)
561 | .build(getActivity());
562 | getCardStream().addCard(c);
563 |
564 | // Explanation
565 | c = new Card.Builder(this, CARD_EXPLANATION)
566 | .setDescription(getString(R.string.explanation_description))
567 | .addAction(getString(R.string.action_notagain),
568 | ACTION_EXPLANATION_DISMISS, Card.ACTION_POSITIVE)
569 | .build(getActivity());
570 | getCardStream().addCard(c);
571 |
572 | // Error
573 | c = new Card.Builder(this, CARD_NOBATCHSUPPORT)
574 | .setTitle(getString(R.string.error_title))
575 | .setDescription(getString(R.string.error_nosensor))
576 | .build(getActivity());
577 | getCardStream().addCard(c);
578 | }
579 |
580 | /**
581 | * Returns the cached CardStreamFragment used to show cards.
582 | *
583 | * @return
584 | */
585 | private CardStreamFragment getCardStream() {
586 | if (mCards == null) {
587 | mCards = ((CardStream) getActivity()).getCardStream();
588 | }
589 | return mCards;
590 | }
591 |
592 | }
593 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/batchstepsensor/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 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.os.Bundle;
20 | import android.support.v4.app.FragmentManager;
21 | import android.support.v4.app.FragmentTransaction;
22 | import android.view.Menu;
23 |
24 | import com.example.android.common.activities.SampleActivityBase;
25 | import com.example.android.common.logger.Log;
26 |
27 | import com.example.android.batchstepsensor.cardstream.CardStream;
28 | import com.example.android.batchstepsensor.cardstream.CardStreamFragment;
29 | import com.example.android.batchstepsensor.cardstream.CardStreamState;
30 | import com.example.android.batchstepsensor.cardstream.OnCardClickListener;
31 | import com.example.android.batchstepsensor.cardstream.StreamRetentionFragment;
32 |
33 | public class MainActivity extends SampleActivityBase implements CardStream {
34 | public static final String TAG = "MainActivity";
35 | public static final String FRAGTAG = "BatchStepSensorFragment";
36 |
37 | private CardStreamFragment mCardStreamFragment;
38 |
39 | private StreamRetentionFragment mRetentionFragment;
40 | private static final String RETENTION_TAG = "retention";
41 |
42 | @Override
43 | protected void onCreate(Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | setContentView(R.layout.activity_main);
46 |
47 | FragmentManager fm = getSupportFragmentManager();
48 | BatchStepSensorFragment fragment =
49 | (BatchStepSensorFragment) fm.findFragmentByTag(FRAGTAG);
50 |
51 | if (fragment == null) {
52 | FragmentTransaction transaction = fm.beginTransaction();
53 | fragment = new BatchStepSensorFragment();
54 | transaction.add(fragment, FRAGTAG);
55 | transaction.commit();
56 | }
57 |
58 | // Use fragment as click listener for cards, but must implement correct interface
59 | if (!(fragment instanceof OnCardClickListener)){
60 | throw new ClassCastException("BatchStepSensorFragment must " +
61 | "implement OnCardClickListener interface.");
62 | }
63 | OnCardClickListener clickListener = (OnCardClickListener) fm.findFragmentByTag(FRAGTAG);
64 |
65 | mRetentionFragment = (StreamRetentionFragment) fm.findFragmentByTag(RETENTION_TAG);
66 | if (mRetentionFragment == null) {
67 | mRetentionFragment = new StreamRetentionFragment();
68 | fm.beginTransaction().add(mRetentionFragment, RETENTION_TAG).commit();
69 | } else {
70 | // If the retention fragment already existed, we need to pull some state.
71 | // pull state out
72 | CardStreamState state = mRetentionFragment.getCardStream();
73 |
74 | // dump it in CardStreamFragment.
75 | mCardStreamFragment =
76 | (CardStreamFragment) fm.findFragmentById(R.id.fragment_cardstream);
77 | mCardStreamFragment.restoreState(state, clickListener);
78 | }
79 | }
80 |
81 | public CardStreamFragment getCardStream() {
82 | if (mCardStreamFragment == null) {
83 | mCardStreamFragment = (CardStreamFragment)
84 | getSupportFragmentManager().findFragmentById(R.id.fragment_cardstream);
85 | }
86 | return mCardStreamFragment;
87 | }
88 |
89 | @Override
90 | protected void onSaveInstanceState(Bundle outState) {
91 | super.onSaveInstanceState(outState);
92 | CardStreamState state = getCardStream().dumpState();
93 | mRetentionFragment.storeCardStream(state);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/batchstepsensor/cardstream/Card.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 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 |
18 | package com.example.android.batchstepsensor.cardstream;
19 |
20 | import android.animation.Animator;
21 | import android.animation.AnimatorListenerAdapter;
22 | import android.animation.ObjectAnimator;
23 | import android.app.Activity;
24 | import android.graphics.Color;
25 | import android.view.LayoutInflater;
26 | import android.view.View;
27 | import android.view.ViewGroup;
28 | import android.widget.Button;
29 | import android.widget.ProgressBar;
30 | import android.widget.TextView;
31 |
32 | import com.example.android.batchstepsensor.R;
33 |
34 | import java.util.ArrayList;
35 |
36 | /**
37 | * A Card contains a description and has a visual state. Optionally a card also contains a title,
38 | * progress indicator and zero or more actions. It is constructed through the {@link Builder}.
39 | */
40 | public class Card {
41 |
42 | public static final int ACTION_POSITIVE = 1;
43 | public static final int ACTION_NEGATIVE = 2;
44 | public static final int ACTION_NEUTRAL = 3;
45 |
46 | public static final int PROGRESS_TYPE_NO_PROGRESS = 0;
47 | public static final int PROGRESS_TYPE_NORMAL = 1;
48 | public static final int PROGRESS_TYPE_INDETERMINATE = 2;
49 | public static final int PROGRESS_TYPE_LABEL = 3;
50 |
51 | private OnCardClickListener mClickListener;
52 |
53 |
54 | // The card model contains a reference to its desired layout (for extensibility), title,
55 | // description, zero to many action buttons, and zero or 1 progress indicators.
56 | private int mLayoutId = R.layout.card;
57 |
58 | /**
59 | * Tag that uniquely identifies this card.
60 | */
61 | private String mTag = null;
62 |
63 | private String mTitle = null;
64 | private String mDescription = null;
65 |
66 | private View mCardView = null;
67 | private View mOverlayView = null;
68 | private TextView mTitleView = null;
69 | private TextView mDescView = null;
70 | private View mActionAreaView = null;
71 |
72 | private Animator mOngoingAnimator = null;
73 |
74 | /**
75 | * Visual state, either {@link #CARD_STATE_NORMAL}, {@link #CARD_STATE_FOCUSED} or
76 | * {@link #CARD_STATE_INACTIVE}.
77 | */
78 | private int mCardState = CARD_STATE_NORMAL;
79 | public static final int CARD_STATE_NORMAL = 1;
80 | public static final int CARD_STATE_FOCUSED = 2;
81 | public static final int CARD_STATE_INACTIVE = 3;
82 |
83 | /**
84 | * Represent actions that can be taken from the card. Stylistically the developer can
85 | * designate the action as positive, negative (ok/cancel, for instance), or neutral.
86 | * This "type" can be used as a UI hint.
87 | * @see com.example.android.sensors.batchstepsensor.Card.CardAction
88 | */
89 | private ArrayList mCardActions = new ArrayList();
90 |
91 | /**
92 | * Some cards will have a sense of "progress" which should be associated with, but separated
93 | * from its "parent" card. To push for simplicity in samples, Cards are designed to have
94 | * a maximum of one progress indicator per Card.
95 | */
96 | private CardProgress mCardProgress = null;
97 |
98 | public Card() {
99 | }
100 |
101 | public String getTag() {
102 | return mTag;
103 | }
104 |
105 | public View getView() {
106 | return mCardView;
107 | }
108 |
109 |
110 | public Card setDescription(String desc) {
111 | if (mDescView != null) {
112 | mDescription = desc;
113 | mDescView.setText(desc);
114 | }
115 | return this;
116 | }
117 |
118 | public Card setTitle(String title) {
119 | if (mTitleView != null) {
120 | mTitle = title;
121 | mTitleView.setText(title);
122 | }
123 | return this;
124 | }
125 |
126 |
127 | /**
128 | * Return the UI state, either {@link #CARD_STATE_NORMAL}, {@link #CARD_STATE_FOCUSED}
129 | * or {@link #CARD_STATE_INACTIVE}.
130 | */
131 | public int getState() {
132 | return mCardState;
133 | }
134 |
135 | /**
136 | * Set the UI state. The parameter describes the state and must be either
137 | * {@link #CARD_STATE_NORMAL}, {@link #CARD_STATE_FOCUSED} or {@link #CARD_STATE_INACTIVE}.
138 | * Note: This method must be called from the UI Thread.
139 | * @param state
140 | * @return The card itself, allows for chaining of calls
141 | */
142 | public Card setState(int state) {
143 | mCardState = state;
144 | if (null != mOverlayView) {
145 | if (null != mOngoingAnimator) {
146 | mOngoingAnimator.end();
147 | mOngoingAnimator = null;
148 | }
149 | switch (state) {
150 | case CARD_STATE_NORMAL: {
151 | mOverlayView.setVisibility(View.GONE);
152 | mOverlayView.setAlpha(1.f);
153 | break;
154 | }
155 | case CARD_STATE_FOCUSED: {
156 | mOverlayView.setVisibility(View.VISIBLE);
157 | mOverlayView.setBackgroundResource(R.drawable.card_overlay_focused);
158 | ObjectAnimator animator = ObjectAnimator.ofFloat(mOverlayView, "alpha", 0.f);
159 | animator.setRepeatMode(ObjectAnimator.REVERSE);
160 | animator.setRepeatCount(ObjectAnimator.INFINITE);
161 | animator.setDuration(1000);
162 | animator.start();
163 | mOngoingAnimator = animator;
164 | break;
165 | }
166 | case CARD_STATE_INACTIVE: {
167 | mOverlayView.setVisibility(View.VISIBLE);
168 | mOverlayView.setAlpha(1.f);
169 | mOverlayView.setBackgroundColor(Color.argb(0xaa, 0xcc, 0xcc, 0xcc));
170 | break;
171 | }
172 | }
173 | }
174 | return this;
175 | }
176 |
177 | /**
178 | * Set the type of progress indicator.
179 | * The progress type can only be changed if the Card was initially build with a progress
180 | * indicator.
181 | * See {@link Builder#setProgressType(int)}.
182 | * Must be a value of either {@link #PROGRESS_TYPE_NORMAL},
183 | * {@link #PROGRESS_TYPE_INDETERMINATE}, {@link #PROGRESS_TYPE_LABEL} or
184 | * {@link #PROGRESS_TYPE_NO_PROGRESS}.
185 | * @param progressType
186 | * @return The card itself, allows for chaining of calls
187 | */
188 | public Card setProgressType(int progressType) {
189 | if (mCardProgress == null) {
190 | mCardProgress = new CardProgress();
191 | }
192 | mCardProgress.setProgressType(progressType);
193 | return this;
194 | }
195 |
196 | /**
197 | * Return the progress indicator type. A value of either {@link #PROGRESS_TYPE_NORMAL},
198 | * {@link #PROGRESS_TYPE_INDETERMINATE}, {@link #PROGRESS_TYPE_LABEL}. Otherwise if no progress
199 | * indicator is enabled, {@link #PROGRESS_TYPE_NO_PROGRESS} is returned.
200 | * @return
201 | */
202 | public int getProgressType() {
203 | if (mCardProgress == null) {
204 | return PROGRESS_TYPE_NO_PROGRESS;
205 | }
206 | return mCardProgress.progressType;
207 | }
208 |
209 | /**
210 | * Set the progress to the specified value. Only applicable if the card has a
211 | * {@link #PROGRESS_TYPE_NORMAL} progress type.
212 | * @param progress
213 | * @return
214 | * @see #setMaxProgress(int)
215 | */
216 | public Card setProgress(int progress) {
217 | if (mCardProgress != null) {
218 | mCardProgress.setProgress(progress);
219 | }
220 | return this;
221 | }
222 |
223 | /**
224 | * Set the range of the progress to 0...max. Only applicable if the card has a
225 | * {@link #PROGRESS_TYPE_NORMAL} progress type.
226 | * @return
227 | */
228 | public Card setMaxProgress(int max){
229 | if (mCardProgress != null) {
230 | mCardProgress.setMax(max);
231 | }
232 | return this;
233 | }
234 |
235 | /**
236 | * Set the label text for the progress if the card has a progress type of
237 | * {@link #PROGRESS_TYPE_NORMAL}, {@link #PROGRESS_TYPE_INDETERMINATE} or
238 | * {@link #PROGRESS_TYPE_LABEL}
239 | * @param text
240 | * @return
241 | */
242 | public Card setProgressLabel(String text) {
243 | if (mCardProgress != null) {
244 | mCardProgress.setProgressLabel(text);
245 | }
246 | return this;
247 | }
248 |
249 | /**
250 | * Toggle the visibility of the progress section of the card. Only applicable if
251 | * the card has a progress type of
252 | * {@link #PROGRESS_TYPE_NORMAL}, {@link #PROGRESS_TYPE_INDETERMINATE} or
253 | * {@link #PROGRESS_TYPE_LABEL}.
254 | * @param isVisible
255 | * @return
256 | */
257 | public Card setProgressVisibility(boolean isVisible) {
258 | if (mCardProgress.progressView == null) {
259 | return this; // Card does not have progress
260 | }
261 | mCardProgress.progressView.setVisibility(isVisible ? View.VISIBLE : View.GONE);
262 |
263 | return this;
264 | }
265 |
266 | /**
267 | * Adds an action to this card during build time.
268 | *
269 | * @param label
270 | * @param id
271 | * @param type
272 | */
273 | private void addAction(String label, int id, int type) {
274 | CardAction cardAction = new CardAction();
275 | cardAction.label = label;
276 | cardAction.id = id;
277 | cardAction.type = type;
278 | mCardActions.add(cardAction);
279 | }
280 |
281 | /**
282 | * Toggles the visibility of a card action.
283 | * @param actionId
284 | * @param isVisible
285 | * @return
286 | */
287 | public Card setActionVisibility(int actionId, boolean isVisible) {
288 | int visibilityFlag = isVisible ? View.VISIBLE : View.GONE;
289 | for (CardAction action : mCardActions) {
290 | if (action.id == actionId && action.actionView != null) {
291 | action.actionView.setVisibility(visibilityFlag);
292 | }
293 | }
294 | return this;
295 | }
296 |
297 | /**
298 | * Toggles visibility of the action area of this Card through an animation.
299 | * @param isVisible
300 | * @return
301 | */
302 | public Card setActionAreaVisibility(boolean isVisible) {
303 | if (mActionAreaView == null) {
304 | return this; // Card does not have an action area
305 | }
306 |
307 | if (isVisible) {
308 | // Show the action area
309 | mActionAreaView.setVisibility(View.VISIBLE);
310 | mActionAreaView.setPivotY(0.f);
311 | mActionAreaView.setPivotX(mCardView.getWidth() / 2.f);
312 | mActionAreaView.setAlpha(0.5f);
313 | mActionAreaView.setRotationX(-90.f);
314 | mActionAreaView.animate().rotationX(0.f).alpha(1.f).setDuration(400);
315 | } else {
316 | // Hide the action area
317 | mActionAreaView.setPivotY(0.f);
318 | mActionAreaView.setPivotX(mCardView.getWidth() / 2.f);
319 | mActionAreaView.animate().rotationX(-90.f).alpha(0.f).setDuration(400).setListener(
320 | new AnimatorListenerAdapter() {
321 | @Override
322 | public void onAnimationEnd(Animator animation) {
323 | mActionAreaView.setVisibility(View.GONE);
324 | }
325 | });
326 | }
327 | return this;
328 | }
329 |
330 |
331 | /**
332 | * Creates a shallow clone of the card. Shallow means all values are present, but no views.
333 | * This is useful for saving/restoring in the case of configuration changes, like screen
334 | * rotation.
335 | *
336 | * @return A shallow clone of the card instance
337 | */
338 | public Card createShallowClone() {
339 | Card cloneCard = new Card();
340 |
341 | // Outer card values
342 | cloneCard.mTitle = mTitle;
343 | cloneCard.mDescription = mDescription;
344 | cloneCard.mTag = mTag;
345 | cloneCard.mLayoutId = mLayoutId;
346 | cloneCard.mCardState = mCardState;
347 |
348 | // Progress
349 | if (mCardProgress != null) {
350 | cloneCard.mCardProgress = mCardProgress.createShallowClone();
351 | }
352 |
353 | // Actions
354 | for (CardAction action : mCardActions) {
355 | cloneCard.mCardActions.add(action.createShallowClone());
356 | }
357 |
358 | return cloneCard;
359 | }
360 |
361 |
362 | /**
363 | * Prepare the card to be stored for configuration change.
364 | */
365 | public void prepareForConfigurationChange() {
366 | // Null out views.
367 | mCardView = null;
368 | for (CardAction action : mCardActions) {
369 | action.actionView = null;
370 | }
371 | mCardProgress.progressView = null;
372 | }
373 |
374 | /**
375 | * Creates a new {@link #Card}.
376 | */
377 | public static class Builder {
378 | private Card mCard;
379 |
380 | /**
381 | * Instantiate the builder with data from a shallow clone.
382 | * @param listener
383 | * @param card
384 | * @see Card#createShallowClone()
385 | */
386 | protected Builder(OnCardClickListener listener, Card card) {
387 | mCard = card;
388 | mCard.mClickListener = listener;
389 | }
390 |
391 | /**
392 | * Instantiate the builder with the tag of the card.
393 | * @param listener
394 | * @param tag
395 | */
396 | public Builder(OnCardClickListener listener, String tag) {
397 | mCard = new Card();
398 | mCard.mTag = tag;
399 | mCard.mClickListener = listener;
400 | }
401 |
402 | public Builder setTitle(String title) {
403 | mCard.mTitle = title;
404 | return this;
405 | }
406 |
407 | public Builder setDescription(String desc) {
408 | mCard.mDescription = desc;
409 | return this;
410 | }
411 |
412 | /**
413 | * Add an action.
414 | * The type describes how this action will be displayed. Accepted values are
415 | * {@link #ACTION_NEUTRAL}, {@link #ACTION_POSITIVE} or {@link #ACTION_NEGATIVE}.
416 | *
417 | * @param label The text to display for this action
418 | * @param id Identifier for this action, supplied in the click listener
419 | * @param type UI style of action
420 | * @return
421 | */
422 | public Builder addAction(String label, int id, int type) {
423 | mCard.addAction(label, id, type);
424 | return this;
425 | }
426 |
427 | /**
428 | * Override the default layout.
429 | * The referenced layout file has to contain the same identifiers as defined in the default
430 | * layout configuration.
431 | * @param layout
432 | * @return
433 | * @see R.layout.card
434 | */
435 | public Builder setLayout(int layout) {
436 | mCard.mLayoutId = layout;
437 | return this;
438 | }
439 |
440 | /**
441 | * Set the type of progress bar to display.
442 | * Accepted values are:
443 | *
444 | * - {@link #PROGRESS_TYPE_NO_PROGRESS} disables the progress indicator
445 | * - {@link #PROGRESS_TYPE_NORMAL}
446 | * displays a standard, linear progress indicator.
447 | * - {@link #PROGRESS_TYPE_INDETERMINATE} displays an indeterminate (infite) progress
448 | * indicator.
449 | * - {@link #PROGRESS_TYPE_LABEL} only displays a label text in the progress area
450 | * of the card.
451 | *
452 | *
453 | * @param progressType
454 | * @return
455 | */
456 | public Builder setProgressType(int progressType) {
457 | mCard.setProgressType(progressType);
458 | return this;
459 | }
460 |
461 | public Builder setProgressLabel(String label) {
462 | // ensure the progress layout has been initialized, use 'no progress' by default
463 | if (mCard.mCardProgress == null) {
464 | mCard.setProgressType(PROGRESS_TYPE_NO_PROGRESS);
465 | }
466 | mCard.mCardProgress.label = label;
467 | return this;
468 | }
469 |
470 | public Builder setProgressMaxValue(int maxValue) {
471 | // ensure the progress layout has been initialized, use 'no progress' by default
472 | if (mCard.mCardProgress == null) {
473 | mCard.setProgressType(PROGRESS_TYPE_NO_PROGRESS);
474 | }
475 | mCard.mCardProgress.maxValue = maxValue;
476 | return this;
477 | }
478 |
479 | public Builder setStatus(int status) {
480 | mCard.setState(status);
481 | return this;
482 | }
483 |
484 | public Card build(Activity activity) {
485 | LayoutInflater inflater = activity.getLayoutInflater();
486 | // Inflating the card.
487 | ViewGroup cardView = (ViewGroup) inflater.inflate(mCard.mLayoutId,
488 | (ViewGroup) activity.findViewById(R.id.card_stream), false);
489 |
490 | // Check that the layout contains a TextView with the card_title id
491 | View viewTitle = cardView.findViewById(R.id.card_title);
492 | if (mCard.mTitle != null && viewTitle != null) {
493 | mCard.mTitleView = (TextView) viewTitle;
494 | mCard.mTitleView.setText(mCard.mTitle);
495 | } else if (viewTitle != null) {
496 | viewTitle.setVisibility(View.GONE);
497 | }
498 |
499 | // Check that the layout contains a TextView with the card_content id
500 | View viewDesc = cardView.findViewById(R.id.card_content);
501 | if (mCard.mDescription != null && viewDesc != null) {
502 | mCard.mDescView = (TextView) viewDesc;
503 | mCard.mDescView.setText(mCard.mDescription);
504 | } else if (viewDesc != null) {
505 | cardView.findViewById(R.id.card_content).setVisibility(View.GONE);
506 | }
507 |
508 |
509 | ViewGroup actionArea = (ViewGroup) cardView.findViewById(R.id.card_actionarea);
510 |
511 | // Inflate Progress
512 | initializeProgressView(inflater, actionArea);
513 |
514 | // Inflate all action views.
515 | initializeActionViews(inflater, cardView, actionArea);
516 |
517 | mCard.mCardView = cardView;
518 | mCard.mOverlayView = cardView.findViewById(R.id.card_overlay);
519 |
520 | return mCard;
521 | }
522 |
523 | /**
524 | * Initialize data from the given card.
525 | * @param card
526 | * @return
527 | * @see Card#createShallowClone()
528 | */
529 | public Builder cloneFromCard(Card card) {
530 | mCard = card.createShallowClone();
531 | return this;
532 | }
533 |
534 | /**
535 | * Build the action views by inflating the appropriate layouts and setting the text and
536 | * values.
537 | * @param inflater
538 | * @param cardView
539 | * @param actionArea
540 | */
541 | private void initializeActionViews(LayoutInflater inflater, ViewGroup cardView,
542 | ViewGroup actionArea) {
543 | if (!mCard.mCardActions.isEmpty()) {
544 | // Set action area to visible only when actions are visible
545 | actionArea.setVisibility(View.VISIBLE);
546 | mCard.mActionAreaView = actionArea;
547 | }
548 |
549 | // Inflate all card actions
550 | for (final CardAction action : mCard.mCardActions) {
551 |
552 | int useActionLayout = 0;
553 | switch (action.type) {
554 | case Card.ACTION_POSITIVE:
555 | useActionLayout = R.layout.card_button_positive;
556 | break;
557 | case Card.ACTION_NEGATIVE:
558 | useActionLayout = R.layout.card_button_negative;
559 | break;
560 | case Card.ACTION_NEUTRAL:
561 | default:
562 | useActionLayout = R.layout.card_button_neutral;
563 | break;
564 | }
565 |
566 | action.actionView = inflater.inflate(useActionLayout, actionArea, false);
567 | Button actionButton = (Button) action.actionView.findViewById(R.id.card_button);
568 |
569 | actionButton.setText(action.label);
570 | actionButton.setOnClickListener(new View.OnClickListener() {
571 | @Override
572 | public void onClick(View v) {
573 | mCard.mClickListener.onCardClick(action.id, mCard.mTag);
574 | }
575 | });
576 | actionArea.addView(action.actionView);
577 | }
578 | }
579 |
580 | /**
581 | * Build the progress view into the given ViewGroup.
582 | *
583 | * @param inflater
584 | * @param actionArea
585 | */
586 | private void initializeProgressView(LayoutInflater inflater, ViewGroup actionArea) {
587 |
588 | // Only inflate progress layout if a progress type other than NO_PROGRESS was set.
589 | if (mCard.mCardProgress != null) {
590 | //Setup progress card.
591 | View progressView = inflater.inflate(R.layout.card_progress, actionArea, false);
592 | ProgressBar progressBar =
593 | (ProgressBar) progressView.findViewById(R.id.card_progress);
594 | ((TextView) progressView.findViewById(R.id.card_progress_text))
595 | .setText(mCard.mCardProgress.label);
596 | progressBar.setMax(mCard.mCardProgress.maxValue);
597 | progressBar.setProgress(0);
598 | mCard.mCardProgress.progressView = progressView;
599 | mCard.mCardProgress.setProgressType(mCard.getProgressType());
600 | actionArea.addView(progressView);
601 | }
602 | }
603 | }
604 |
605 | /**
606 | * Represents a clickable action, accessible from the bottom of the card.
607 | * Fields include the label, an ID to specify the action that was performed in the callback,
608 | * an action type (positive, negative, neutral), and the callback.
609 | */
610 | public class CardAction {
611 |
612 | public String label;
613 | public int id;
614 | public int type;
615 | public View actionView;
616 |
617 | public CardAction createShallowClone() {
618 | CardAction actionClone = new CardAction();
619 | actionClone.label = label;
620 | actionClone.id = id;
621 | actionClone.type = type;
622 | return actionClone;
623 | // Not the view. Never the view (don't want to hold view references for
624 | // onConfigurationChange.
625 | }
626 |
627 | }
628 |
629 | /**
630 | * Describes the progress of a {@link Card}.
631 | * Three types of progress are supported:
632 | * - {@link Card#PROGRESS_TYPE_NORMAL: Standard progress bar with label text
633 | * - {@link Card#PROGRESS_TYPE_INDETERMINATE}: Indeterminate progress bar with label txt
634 | * - {@link Card#PROGRESS_TYPE_LABEL}: Label only, no progresss bar
635 | *
636 | */
637 | public class CardProgress {
638 | private int progressType = Card.PROGRESS_TYPE_NO_PROGRESS;
639 | private String label = "";
640 | private int currProgress = 0;
641 | private int maxValue = 100;
642 |
643 | public View progressView = null;
644 | private ProgressBar progressBar = null;
645 | private TextView progressLabel = null;
646 |
647 | public CardProgress createShallowClone() {
648 | CardProgress progressClone = new CardProgress();
649 | progressClone.label = label;
650 | progressClone.currProgress = currProgress;
651 | progressClone.maxValue = maxValue;
652 | progressClone.progressType = progressType;
653 | return progressClone;
654 | }
655 |
656 | /**
657 | * Set the progress. Only useful for the type {@link #PROGRESS_TYPE_NORMAL}.
658 | * @param progress
659 | * @see android.widget.ProgressBar#setProgress(int)
660 | */
661 | public void setProgress(int progress) {
662 | currProgress = progress;
663 | final ProgressBar bar = getProgressBar();
664 | if (bar != null) {
665 | bar.setProgress(currProgress);
666 | bar.invalidate();
667 | }
668 | }
669 |
670 | /**
671 | * Set the range of the progress to 0...max.
672 | * Only useful for the type {@link #PROGRESS_TYPE_NORMAL}.
673 | * @param max
674 | * @see android.widget.ProgressBar#setMax(int)
675 | */
676 | public void setMax(int max) {
677 | maxValue = max;
678 | final ProgressBar bar = getProgressBar();
679 | if (bar != null) {
680 | bar.setMax(maxValue);
681 | }
682 | }
683 |
684 | /**
685 | * Set the label text that appears near the progress indicator.
686 | * @param text
687 | */
688 | public void setProgressLabel(String text) {
689 | label = text;
690 | final TextView labelView = getProgressLabel();
691 | if (labelView != null) {
692 | labelView.setText(text);
693 | }
694 | }
695 |
696 | /**
697 | * Set how progress is displayed. The parameter must be one of three supported types:
698 | * - {@link Card#PROGRESS_TYPE_NORMAL: Standard progress bar with label text
699 | * - {@link Card#PROGRESS_TYPE_INDETERMINATE}:
700 | * Indeterminate progress bar with label txt
701 | * - {@link Card#PROGRESS_TYPE_LABEL}: Label only, no progresss bar
702 | * @param type
703 | */
704 | public void setProgressType(int type) {
705 | progressType = type;
706 | if (progressView != null) {
707 | switch (type) {
708 | case PROGRESS_TYPE_NO_PROGRESS: {
709 | progressView.setVisibility(View.GONE);
710 | break;
711 | }
712 | case PROGRESS_TYPE_NORMAL: {
713 | progressView.setVisibility(View.VISIBLE);
714 | getProgressBar().setIndeterminate(false);
715 | break;
716 | }
717 | case PROGRESS_TYPE_INDETERMINATE: {
718 | progressView.setVisibility(View.VISIBLE);
719 | getProgressBar().setIndeterminate(true);
720 | break;
721 | }
722 | }
723 | }
724 | }
725 |
726 | private TextView getProgressLabel() {
727 | if (progressLabel != null) {
728 | return progressLabel;
729 | } else if (progressView != null) {
730 | progressLabel = (TextView) progressView.findViewById(R.id.card_progress_text);
731 | return progressLabel;
732 | } else {
733 | return null;
734 | }
735 | }
736 |
737 | private ProgressBar getProgressBar() {
738 | if (progressBar != null) {
739 | return progressBar;
740 | } else if (progressView != null) {
741 | progressBar = (ProgressBar) progressView.findViewById(R.id.card_progress);
742 | return progressBar;
743 | } else {
744 | return null;
745 | }
746 | }
747 |
748 | }
749 | }
750 |
751 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/batchstepsensor/cardstream/CardActionButton.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 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 |
18 | package com.example.android.batchstepsensor.cardstream;
19 |
20 | import android.content.Context;
21 | import android.os.Build;
22 | import android.support.v4.view.ViewCompat;
23 | import android.util.AttributeSet;
24 | import android.view.MotionEvent;
25 | import android.view.animation.BounceInterpolator;
26 | import android.view.animation.DecelerateInterpolator;
27 | import android.widget.Button;
28 |
29 | /**
30 | * Custom Button with a special 'pressed' effect for touch events.
31 | */
32 | public class CardActionButton extends Button {
33 |
34 | public CardActionButton(Context context) {
35 | super(context);
36 | }
37 |
38 | public CardActionButton(Context context, AttributeSet attrs) {
39 | super(context, attrs);
40 | }
41 |
42 | public CardActionButton(Context context, AttributeSet attrs, int defStyle) {
43 | super(context, attrs, defStyle);
44 | }
45 |
46 | @Override
47 | public boolean onTouchEvent(MotionEvent event) {
48 |
49 | switch (event.getAction()) {
50 | case MotionEvent.ACTION_DOWN: {
51 | setPressed(true);
52 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
53 | animate().scaleX(0.98f).scaleY(0.98f).setDuration(100)
54 | .setInterpolator(new DecelerateInterpolator());
55 | } else {
56 | ViewCompat.setElevation(this, 8.f);
57 | }
58 | break;
59 | }
60 | case MotionEvent.ACTION_UP:
61 | case MotionEvent.ACTION_CANCEL: {
62 | setPressed(false);
63 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
64 | animate().scaleX(1.f).scaleY(1.f).setDuration(50)
65 | .setInterpolator(new BounceInterpolator());
66 | } else {
67 | ViewCompat.setElevation(this, 0.f);
68 | }
69 | break;
70 | }
71 | }
72 |
73 | return super.onTouchEvent(event);
74 | }
75 |
76 | }
77 |
78 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/batchstepsensor/cardstream/CardLayout.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 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 |
18 | package com.example.android.batchstepsensor.cardstream;
19 |
20 | import android.content.Context;
21 | import android.util.AttributeSet;
22 | import android.view.MotionEvent;
23 | import android.view.ViewConfiguration;
24 | import android.widget.RelativeLayout;
25 |
26 | /**
27 | * Custom Button with a special 'pressed' effect for touch events.
28 | */
29 | public class CardLayout extends RelativeLayout {
30 |
31 | private boolean mSwiping = false;
32 | private float mDownX = 0.f;
33 | private float mDownY = 0.f;
34 | private float mTouchSlop = 0.f;
35 |
36 | public CardLayout(Context context) {
37 | super(context);
38 | init();
39 | }
40 |
41 | public CardLayout(Context context, AttributeSet attrs) {
42 | super(context, attrs);
43 | init();
44 | }
45 |
46 | public CardLayout(Context context, AttributeSet attrs, int defStyle) {
47 | super(context, attrs, defStyle);
48 | init();
49 | }
50 |
51 | private void init(){
52 | setFocusable(true);
53 | setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
54 | setWillNotDraw(false);
55 | setClickable(true);
56 |
57 | mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop() * 2.f;
58 | }
59 |
60 | @Override
61 | public boolean onTouchEvent(MotionEvent event) {
62 | switch(event.getAction()){
63 | case MotionEvent.ACTION_CANCEL:
64 | case MotionEvent.ACTION_UP:
65 | mSwiping = false;
66 | break;
67 | }
68 | return super.onTouchEvent(event);
69 | }
70 |
71 | @Override
72 | public boolean onInterceptTouchEvent(MotionEvent event) {
73 |
74 | switch(event.getAction()){
75 | case MotionEvent.ACTION_MOVE:
76 | if( !mSwiping ){
77 | mSwiping = Math.abs(mDownX - event.getX()) > mTouchSlop;
78 | }
79 | break;
80 | case MotionEvent.ACTION_DOWN:
81 | mDownX = event.getX();
82 | mDownY = event.getY();
83 | mSwiping = false;
84 | break;
85 | case MotionEvent.ACTION_CANCEL:
86 | case MotionEvent.ACTION_UP:
87 | mSwiping = false;
88 | break;
89 | }
90 | return mSwiping;
91 | }
92 | }
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/batchstepsensor/cardstream/CardStream.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 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 |
18 | package com.example.android.batchstepsensor.cardstream;
19 |
20 | public interface CardStream {
21 | public CardStreamFragment getCardStream();
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/batchstepsensor/cardstream/CardStreamAnimator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 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 |
18 | package com.example.android.batchstepsensor.cardstream;
19 |
20 | import android.animation.ObjectAnimator;
21 | import android.content.Context;
22 | import android.view.View;
23 |
24 | /**
25 | * An abstract class which defines animators for CardStreamLinearLayout.
26 | */
27 | abstract class CardStreamAnimator {
28 |
29 | protected float mSpeedFactor = 1.f;
30 |
31 | /**
32 | * Set speed factor of animations. Higher value means longer duration & slow animation.
33 | *
34 | * @param speedFactor speed type 1: SLOW, 2: NORMAL, 3:FAST
35 | */
36 | public void setSpeedFactor(float speedFactor) {
37 | mSpeedFactor = speedFactor;
38 | }
39 |
40 | /**
41 | * Define initial animation of each child which fired when a user rotate a screen.
42 | *
43 | * @param context
44 | * @return ObjectAnimator for initial animation
45 | */
46 | public abstract ObjectAnimator getInitalAnimator(Context context);
47 |
48 | /**
49 | * Define disappearing animation of a child which fired when a view is removed programmatically
50 | *
51 | * @param context
52 | * @return ObjectAnimator for disappearing animation
53 | */
54 | public abstract ObjectAnimator getDisappearingAnimator(Context context);
55 |
56 | /**
57 | * Define appearing animation of a child which fired when a view is added programmatically
58 | *
59 | * @param context
60 | * @return ObjectAnimator for appearing animation
61 | */
62 | public abstract ObjectAnimator getAppearingAnimator(Context context);
63 |
64 | /**
65 | * Define swipe-in (back to the origin position) animation of a child
66 | * which fired when a view is not moved enough to be removed.
67 | *
68 | * @param view target view
69 | * @param deltaX delta distance by x-axis
70 | * @param deltaY delta distance by y-axis
71 | * @return ObjectAnimator for swipe-in animation
72 | */
73 | public abstract ObjectAnimator getSwipeInAnimator(View view, float deltaX, float deltaY);
74 |
75 | /**
76 | * Define swipe-out animation of a child
77 | * which fired when a view is removing by a user swipe action.
78 | *
79 | * @param view target view
80 | * @param deltaX delta distance by x-axis
81 | * @param deltaY delta distance by y-axis
82 | * @return ObjectAnimator for swipe-out animation
83 | */
84 | public abstract ObjectAnimator getSwipeOutAnimator(View view, float deltaX, float deltaY);
85 |
86 | /**
87 | * A simple CardStreamAnimator implementation which is used to turn animations off.
88 | */
89 | public static class EmptyAnimator extends CardStreamAnimator {
90 |
91 | @Override
92 | public ObjectAnimator getInitalAnimator(Context context) {
93 | return null;
94 | }
95 |
96 | @Override
97 | public ObjectAnimator getDisappearingAnimator(Context context) {
98 | return null;
99 | }
100 |
101 | @Override
102 | public ObjectAnimator getAppearingAnimator(Context context) {
103 | return null;
104 | }
105 |
106 | @Override
107 | public ObjectAnimator getSwipeInAnimator(View view, float deltaX, float deltaY) {
108 | return null;
109 | }
110 |
111 | @Override
112 | public ObjectAnimator getSwipeOutAnimator(View view, float deltaX, float deltaY) {
113 | return null;
114 | }
115 | }
116 |
117 | }
118 |
119 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/batchstepsensor/cardstream/CardStreamFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 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 |
18 | package com.example.android.batchstepsensor.cardstream;
19 |
20 | import android.os.Bundle;
21 | import android.support.v4.app.Fragment;
22 | import android.view.LayoutInflater;
23 | import android.view.View;
24 | import android.view.ViewGroup;
25 |
26 | import java.util.Collection;
27 | import java.util.HashMap;
28 | import java.util.HashSet;
29 | import java.util.LinkedHashMap;
30 |
31 | import com.example.android.batchstepsensor.R;
32 |
33 | /**
34 | * A Fragment that handles a stream of cards.
35 | * Cards can be shown or hidden. When a card is shown it can also be marked as not-dismissible, see
36 | * {@link CardStreamLinearLayout#addCard(android.view.View, boolean)}.
37 | */
38 | public class CardStreamFragment extends Fragment {
39 |
40 | private static final int INITIAL_SIZE = 15;
41 | private CardStreamLinearLayout mLayout = null;
42 | private LinkedHashMap mVisibleCards = new LinkedHashMap(INITIAL_SIZE);
43 | private HashMap mHiddenCards = new HashMap(INITIAL_SIZE);
44 | private HashSet mDismissibleCards = new HashSet(INITIAL_SIZE);
45 |
46 | // Set the listener to handle dismissed cards by moving them to the hidden cards map.
47 | private CardStreamLinearLayout.OnDissmissListener mCardDismissListener =
48 | new CardStreamLinearLayout.OnDissmissListener() {
49 | @Override
50 | public void onDismiss(String tag) {
51 | dismissCard(tag);
52 | }
53 | };
54 |
55 |
56 | @Override
57 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
58 | Bundle savedInstanceState) {
59 |
60 | View view = inflater.inflate(R.layout.cardstream, container, false);
61 | mLayout = (CardStreamLinearLayout) view.findViewById(R.id.card_stream);
62 | mLayout.setOnDismissListener(mCardDismissListener);
63 |
64 | return view;
65 | }
66 |
67 | /**
68 | * Add a visible, dismissible card to the card stream.
69 | *
70 | * @param card
71 | */
72 | public void addCard(Card card) {
73 | final String tag = card.getTag();
74 |
75 | if (!mVisibleCards.containsKey(tag) && !mHiddenCards.containsKey(tag)) {
76 | final View view = card.getView();
77 | view.setTag(tag);
78 | mHiddenCards.put(tag, card);
79 | }
80 | }
81 |
82 | /**
83 | * Add and show a card.
84 | *
85 | * @param card
86 | * @param show
87 | */
88 | public void addCard(Card card, boolean show) {
89 | addCard(card);
90 | if (show) {
91 | showCard(card.getTag());
92 | }
93 | }
94 |
95 | /**
96 | * Remove a card and return true if it has been successfully removed.
97 | *
98 | * @param tag
99 | * @return
100 | */
101 | public boolean removeCard(String tag) {
102 | // Attempt to remove a visible card first
103 | Card card = mVisibleCards.get(tag);
104 | if (card != null) {
105 | // Card is visible, also remove from layout
106 | mVisibleCards.remove(tag);
107 | mLayout.removeView(card.getView());
108 | return true;
109 | } else {
110 | // Card is hidden, no need to remove from layout
111 | card = mHiddenCards.remove(tag);
112 | return card != null;
113 | }
114 | }
115 |
116 | /**
117 | * Show a dismissible card, returns false if the card could not be shown.
118 | *
119 | * @param tag
120 | * @return
121 | */
122 | public boolean showCard(String tag) {
123 | return showCard(tag, true);
124 | }
125 |
126 | /**
127 | * Show a card, returns false if the card could not be shown.
128 | *
129 | * @param tag
130 | * @param dismissible
131 | * @return
132 | */
133 | public boolean showCard(String tag, boolean dismissible) {
134 | final Card card = mHiddenCards.get(tag);
135 | // ensure the card is hidden and not already visible
136 | if (card != null && !mVisibleCards.containsValue(tag)) {
137 | mHiddenCards.remove(tag);
138 | mVisibleCards.put(tag, card);
139 | mLayout.addCard(card.getView(), dismissible);
140 | if (dismissible) {
141 | mDismissibleCards.add(tag);
142 | }
143 | return true;
144 | }
145 | return false;
146 | }
147 |
148 | /**
149 | * Hides the card, returns false if the card could not be hidden.
150 | *
151 | * @param tag
152 | * @return
153 | */
154 | public boolean hideCard(String tag) {
155 | final Card card = mVisibleCards.get(tag);
156 | if (card != null) {
157 | mVisibleCards.remove(tag);
158 | mDismissibleCards.remove(tag);
159 | mHiddenCards.put(tag, card);
160 |
161 | mLayout.removeView(card.getView());
162 | return true;
163 | }
164 | return mHiddenCards.containsValue(tag);
165 | }
166 |
167 |
168 | private void dismissCard(String tag) {
169 | final Card card = mVisibleCards.get(tag);
170 | if (card != null) {
171 | mDismissibleCards.remove(tag);
172 | mVisibleCards.remove(tag);
173 | mHiddenCards.put(tag, card);
174 | }
175 | }
176 |
177 |
178 | public boolean isCardVisible(String tag) {
179 | return mVisibleCards.containsValue(tag);
180 | }
181 |
182 | /**
183 | * Returns true if the card is shown and is dismissible.
184 | *
185 | * @param tag
186 | * @return
187 | */
188 | public boolean isCardDismissible(String tag) {
189 | return mDismissibleCards.contains(tag);
190 | }
191 |
192 | /**
193 | * Returns the Card for this tag.
194 | *
195 | * @param tag
196 | * @return
197 | */
198 | public Card getCard(String tag) {
199 | final Card card = mVisibleCards.get(tag);
200 | if (card != null) {
201 | return card;
202 | } else {
203 | return mHiddenCards.get(tag);
204 | }
205 | }
206 |
207 | /**
208 | * Moves the view port to show the card with this tag.
209 | *
210 | * @param tag
211 | * @see CardStreamLinearLayout#setFirstVisibleCard(String)
212 | */
213 | public void setFirstVisibleCard(String tag) {
214 | final Card card = mVisibleCards.get(tag);
215 | if (card != null) {
216 | mLayout.setFirstVisibleCard(tag);
217 | }
218 | }
219 |
220 | public int getVisibleCardCount() {
221 | return mVisibleCards.size();
222 | }
223 |
224 | public Collection getVisibleCards() {
225 | return mVisibleCards.values();
226 | }
227 |
228 | public void restoreState(CardStreamState state, OnCardClickListener callback) {
229 | // restore hidden cards
230 | for (Card c : state.hiddenCards) {
231 | Card card = new Card.Builder(callback,c).build(getActivity());
232 | mHiddenCards.put(card.getTag(), card);
233 | }
234 |
235 | // temporarily set up list of dismissible
236 | final HashSet dismissibleCards = state.dismissibleCards;
237 |
238 | //restore shown cards
239 | for (Card c : state.visibleCards) {
240 | Card card = new Card.Builder(callback,c).build(getActivity());
241 | addCard(card);
242 | final String tag = card.getTag();
243 | showCard(tag, dismissibleCards.contains(tag));
244 | }
245 |
246 | // move to first visible card
247 | final String firstShown = state.shownTag;
248 | if (firstShown != null) {
249 | mLayout.setFirstVisibleCard(firstShown);
250 | }
251 |
252 | mLayout.triggerShowInitialAnimation();
253 | }
254 |
255 | public CardStreamState dumpState() {
256 | final Card[] visible = cloneCards(mVisibleCards.values());
257 | final Card[] hidden = cloneCards(mHiddenCards.values());
258 | final HashSet dismissible = new HashSet(mDismissibleCards);
259 | final String firstVisible = mLayout.getFirstVisibleCardTag();
260 |
261 | return new CardStreamState(visible, hidden, dismissible, firstVisible);
262 | }
263 |
264 | private Card[] cloneCards(Collection cards) {
265 | Card[] cardArray = new Card[cards.size()];
266 | int i = 0;
267 | for (Card c : cards) {
268 | cardArray[i++] = c.createShallowClone();
269 | }
270 |
271 | return cardArray;
272 | }
273 |
274 | }
275 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/batchstepsensor/cardstream/CardStreamLinearLayout.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 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 |
18 | package com.example.android.batchstepsensor.cardstream;
19 |
20 | import android.animation.Animator;
21 | import android.animation.LayoutTransition;
22 | import android.animation.ObjectAnimator;
23 | import android.annotation.SuppressLint;
24 | import android.annotation.TargetApi;
25 | import android.content.Context;
26 | import android.content.res.TypedArray;
27 | import android.graphics.Rect;
28 | import android.os.Build;
29 | import android.util.AttributeSet;
30 | import android.view.MotionEvent;
31 | import android.view.View;
32 | import android.view.ViewConfiguration;
33 | import android.view.ViewGroup;
34 | import android.view.ViewParent;
35 | import android.widget.LinearLayout;
36 | import android.widget.ScrollView;
37 |
38 | import com.example.android.common.logger.Log;
39 | import com.example.android.batchstepsensor.R;
40 |
41 | import java.util.ArrayList;
42 |
43 | /**
44 | * A Layout that contains a stream of card views.
45 | */
46 | public class CardStreamLinearLayout extends LinearLayout {
47 |
48 | public static final int ANIMATION_SPEED_SLOW = 1001;
49 | public static final int ANIMATION_SPEED_NORMAL = 1002;
50 | public static final int ANIMATION_SPEED_FAST = 1003;
51 |
52 | private static final String TAG = "CardStreamLinearLayout";
53 | private final ArrayList mFixedViewList = new ArrayList();
54 | private final Rect mChildRect = new Rect();
55 | private CardStreamAnimator mAnimators;
56 | private OnDissmissListener mDismissListener = null;
57 | private boolean mLayouted = false;
58 | private boolean mSwiping = false;
59 | private String mFirstVisibleCardTag = null;
60 | private boolean mShowInitialAnimation = false;
61 |
62 | /**
63 | * Handle touch events to fade/move dragged items as they are swiped out
64 | */
65 | private OnTouchListener mTouchListener = new OnTouchListener() {
66 |
67 | private float mDownX;
68 | private float mDownY;
69 |
70 | @Override
71 | public boolean onTouch(final View v, MotionEvent event) {
72 |
73 | switch (event.getAction()) {
74 | case MotionEvent.ACTION_DOWN:
75 | mDownX = event.getX();
76 | mDownY = event.getY();
77 | break;
78 | case MotionEvent.ACTION_CANCEL:
79 | resetAnimatedView(v);
80 | mSwiping = false;
81 | mDownX = 0.f;
82 | mDownY = 0.f;
83 | break;
84 | case MotionEvent.ACTION_MOVE: {
85 |
86 | float x = event.getX() + v.getTranslationX();
87 | float y = event.getY() + v.getTranslationY();
88 |
89 | mDownX = mDownX == 0.f ? x : mDownX;
90 | mDownY = mDownY == 0.f ? x : mDownY;
91 |
92 | float deltaX = x - mDownX;
93 | float deltaY = y - mDownY;
94 |
95 | if (!mSwiping && isSwiping(deltaX, deltaY)) {
96 | mSwiping = true;
97 | v.getParent().requestDisallowInterceptTouchEvent(true);
98 | } else {
99 | swipeView(v, deltaX, deltaY);
100 | }
101 | }
102 | break;
103 | case MotionEvent.ACTION_UP: {
104 | // User let go - figure out whether to animate the view out, or back into place
105 | if (mSwiping) {
106 | float x = event.getX() + v.getTranslationX();
107 | float y = event.getY() + v.getTranslationY();
108 |
109 | float deltaX = x - mDownX;
110 | float deltaY = y - mDownX;
111 | float deltaXAbs = Math.abs(deltaX);
112 |
113 | // User let go - figure out whether to animate the view out, or back into place
114 | boolean remove = deltaXAbs > v.getWidth() / 4 && !isFixedView(v);
115 | if( remove )
116 | handleViewSwipingOut(v, deltaX, deltaY);
117 | else
118 | handleViewSwipingIn(v, deltaX, deltaY);
119 | }
120 | mDownX = 0.f;
121 | mDownY = 0.f;
122 | mSwiping = false;
123 | }
124 | break;
125 | default:
126 | return false;
127 | }
128 | return false;
129 | }
130 | };
131 | private int mSwipeSlop = -1;
132 | /**
133 | * Handle end-transition animation event of each child and launch a following animation.
134 | */
135 | private LayoutTransition.TransitionListener mTransitionListener
136 | = new LayoutTransition.TransitionListener() {
137 |
138 | @Override
139 | public void startTransition(LayoutTransition transition, ViewGroup container, View
140 | view, int transitionType) {
141 | Log.d(TAG, "Start LayoutTransition animation:" + transitionType);
142 | }
143 |
144 | @Override
145 | public void endTransition(LayoutTransition transition, ViewGroup container,
146 | final View view, int transitionType) {
147 |
148 | Log.d(TAG, "End LayoutTransition animation:" + transitionType);
149 | if (transitionType == LayoutTransition.APPEARING) {
150 | final View area = view.findViewById(R.id.card_actionarea);
151 | if (area != null) {
152 | runShowActionAreaAnimation(container, area);
153 | }
154 | }
155 | }
156 | };
157 | /**
158 | * Handle a hierarchy change event
159 | * when a new child is added, scroll to bottom and hide action area..
160 | */
161 | private OnHierarchyChangeListener mOnHierarchyChangeListener
162 | = new OnHierarchyChangeListener() {
163 | @Override
164 | public void onChildViewAdded(final View parent, final View child) {
165 |
166 | Log.d(TAG, "child is added: " + child);
167 |
168 | ViewParent scrollView = parent.getParent();
169 | if (scrollView != null && scrollView instanceof ScrollView) {
170 | ((ScrollView) scrollView).fullScroll(FOCUS_DOWN);
171 | }
172 |
173 | if (getLayoutTransition() != null) {
174 | View view = child.findViewById(R.id.card_actionarea);
175 | if (view != null)
176 | view.setAlpha(0.f);
177 | }
178 | }
179 |
180 | @Override
181 | public void onChildViewRemoved(View parent, View child) {
182 | Log.d(TAG, "child is removed: " + child);
183 | mFixedViewList.remove(child);
184 | }
185 | };
186 | private int mLastDownX;
187 |
188 | public CardStreamLinearLayout(Context context) {
189 | super(context);
190 | initialize(null, 0);
191 | }
192 |
193 | public CardStreamLinearLayout(Context context, AttributeSet attrs) {
194 | super(context, attrs);
195 | initialize(attrs, 0);
196 | }
197 |
198 | @SuppressLint("NewApi")
199 | public CardStreamLinearLayout(Context context, AttributeSet attrs, int defStyle) {
200 | super(context, attrs, defStyle);
201 | initialize(attrs, defStyle);
202 | }
203 |
204 | /**
205 | * add a card view w/ canDismiss flag.
206 | *
207 | * @param cardView a card view
208 | * @param canDismiss flag to indicate this card is dismissible or not.
209 | */
210 | public void addCard(View cardView, boolean canDismiss) {
211 | if (cardView.getParent() == null) {
212 | initCard(cardView, canDismiss);
213 |
214 | ViewGroup.LayoutParams param = cardView.getLayoutParams();
215 | if(param == null)
216 | param = generateDefaultLayoutParams();
217 |
218 | super.addView(cardView, -1, param);
219 | }
220 | }
221 |
222 | @Override
223 | public void addView(View child, int index, ViewGroup.LayoutParams params) {
224 | if (child.getParent() == null) {
225 | initCard(child, true);
226 | super.addView(child, index, params);
227 | }
228 | }
229 |
230 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
231 | @Override
232 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
233 | super.onLayout(changed, l, t, r, b);
234 | Log.d(TAG, "onLayout: " + changed);
235 |
236 | if( changed && !mLayouted ){
237 | mLayouted = true;
238 |
239 | ObjectAnimator animator;
240 | LayoutTransition layoutTransition = new LayoutTransition();
241 |
242 | animator = mAnimators.getDisappearingAnimator(getContext());
243 | layoutTransition.setAnimator(LayoutTransition.DISAPPEARING, animator);
244 |
245 | animator = mAnimators.getAppearingAnimator(getContext());
246 | layoutTransition.setAnimator(LayoutTransition.APPEARING, animator);
247 |
248 | layoutTransition.addTransitionListener(mTransitionListener);
249 |
250 | if( animator != null )
251 | layoutTransition.setDuration(animator.getDuration());
252 |
253 | setLayoutTransition(layoutTransition);
254 |
255 | if( mShowInitialAnimation )
256 | runInitialAnimations();
257 |
258 | if (mFirstVisibleCardTag != null) {
259 | scrollToCard(mFirstVisibleCardTag);
260 | mFirstVisibleCardTag = null;
261 | }
262 | }
263 | }
264 |
265 | /**
266 | * Check whether a user moved enough distance to start a swipe action or not.
267 | *
268 | * @param deltaX
269 | * @param deltaY
270 | * @return true if a user is swiping.
271 | */
272 | protected boolean isSwiping(float deltaX, float deltaY) {
273 |
274 | if (mSwipeSlop < 0) {
275 | //get swipping slop from ViewConfiguration;
276 | mSwipeSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
277 | }
278 |
279 | boolean swipping = false;
280 | float absDeltaX = Math.abs(deltaX);
281 |
282 | if( absDeltaX > mSwipeSlop )
283 | return true;
284 |
285 | return swipping;
286 | }
287 |
288 | /**
289 | * Swipe a view by moving distance
290 | *
291 | * @param child a target view
292 | * @param deltaX x moving distance by x-axis.
293 | * @param deltaY y moving distance by y-axis.
294 | */
295 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
296 | protected void swipeView(View child, float deltaX, float deltaY) {
297 | if (isFixedView(child)){
298 | deltaX = deltaX / 4;
299 | }
300 |
301 | float deltaXAbs = Math.abs(deltaX);
302 | float fractionCovered = deltaXAbs / (float) child.getWidth();
303 |
304 | child.setTranslationX(deltaX);
305 | child.setAlpha(1.f - fractionCovered);
306 |
307 | if (deltaX > 0)
308 | child.setRotationY(-15.f * fractionCovered);
309 | else
310 | child.setRotationY(15.f * fractionCovered);
311 | }
312 |
313 | protected void notifyOnDismissEvent( View child ){
314 | if( child == null || mDismissListener == null )
315 | return;
316 |
317 | mDismissListener.onDismiss((String) child.getTag());
318 | }
319 |
320 | /**
321 | * get the tag of the first visible child in this layout
322 | *
323 | * @return tag of the first visible child or null
324 | */
325 | public String getFirstVisibleCardTag() {
326 |
327 | final int count = getChildCount();
328 |
329 | if (count == 0)
330 | return null;
331 |
332 | for (int index = 0; index < count; ++index) {
333 | //check the position of each view.
334 | View child = getChildAt(index);
335 | if (child.getGlobalVisibleRect(mChildRect) == true)
336 | return (String) child.getTag();
337 | }
338 |
339 | return null;
340 | }
341 |
342 | /**
343 | * Set the first visible card of this linear layout.
344 | *
345 | * @param tag tag of a card which should already added to this layout.
346 | */
347 | public void setFirstVisibleCard(String tag) {
348 | if (tag == null)
349 | return; //do nothing.
350 |
351 | if (mLayouted) {
352 | scrollToCard(tag);
353 | } else {
354 | //keep the tag for next use.
355 | mFirstVisibleCardTag = tag;
356 | }
357 | }
358 |
359 | /**
360 | * If this flag is set,
361 | * after finishing initial onLayout event, an initial animation which is defined in DefaultCardStreamAnimator is launched.
362 | */
363 | public void triggerShowInitialAnimation(){
364 | mShowInitialAnimation = true;
365 | }
366 |
367 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
368 | public void setCardStreamAnimator( CardStreamAnimator animators ){
369 |
370 | if( animators == null )
371 | mAnimators = new CardStreamAnimator.EmptyAnimator();
372 | else
373 | mAnimators = animators;
374 |
375 | LayoutTransition layoutTransition = getLayoutTransition();
376 |
377 | if( layoutTransition != null ){
378 | layoutTransition.setAnimator( LayoutTransition.APPEARING,
379 | mAnimators.getAppearingAnimator(getContext()) );
380 | layoutTransition.setAnimator( LayoutTransition.DISAPPEARING,
381 | mAnimators.getDisappearingAnimator(getContext()) );
382 | }
383 | }
384 |
385 | /**
386 | * set a OnDismissListener which called when user dismiss a card.
387 | *
388 | * @param listener
389 | */
390 | public void setOnDismissListener(OnDissmissListener listener) {
391 | mDismissListener = listener;
392 | }
393 |
394 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
395 | private void initialize(AttributeSet attrs, int defStyle) {
396 |
397 | float speedFactor = 1.f;
398 |
399 | if (attrs != null) {
400 | TypedArray a = getContext().obtainStyledAttributes(attrs,
401 | R.styleable.CardStream, defStyle, 0);
402 |
403 | if( a != null ){
404 | int speedType = a.getInt(R.styleable.CardStream_animationDuration, 1001);
405 | switch (speedType){
406 | case ANIMATION_SPEED_FAST:
407 | speedFactor = 0.5f;
408 | break;
409 | case ANIMATION_SPEED_NORMAL:
410 | speedFactor = 1.f;
411 | break;
412 | case ANIMATION_SPEED_SLOW:
413 | speedFactor = 2.f;
414 | break;
415 | }
416 |
417 | String animatorName = a.getString(R.styleable.CardStream_animators);
418 |
419 | try {
420 | if( animatorName != null )
421 | mAnimators = (CardStreamAnimator) getClass().getClassLoader()
422 | .loadClass(animatorName).newInstance();
423 | } catch (Exception e) {
424 | Log.e(TAG, "Fail to load animator:" + animatorName, e);
425 | } finally {
426 | if(mAnimators == null)
427 | mAnimators = new DefaultCardStreamAnimator();
428 | }
429 | a.recycle();
430 | }
431 | }
432 |
433 | mAnimators.setSpeedFactor(speedFactor);
434 | mSwipeSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
435 | setOnHierarchyChangeListener(mOnHierarchyChangeListener);
436 | }
437 |
438 | private void initCard(View cardView, boolean canDismiss) {
439 | resetAnimatedView(cardView);
440 | cardView.setOnTouchListener(mTouchListener);
441 | if (!canDismiss)
442 | mFixedViewList.add(cardView);
443 | }
444 |
445 | private boolean isFixedView(View v) {
446 | return mFixedViewList.contains(v);
447 | }
448 |
449 | private void resetAnimatedView(View child) {
450 | child.setAlpha(1.f);
451 | child.setTranslationX(0.f);
452 | child.setTranslationY(0.f);
453 | child.setRotation(0.f);
454 | child.setRotationY(0.f);
455 | child.setRotationX(0.f);
456 | child.setScaleX(1.f);
457 | child.setScaleY(1.f);
458 | }
459 |
460 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
461 | private void runInitialAnimations() {
462 | if( mAnimators == null )
463 | return;
464 |
465 | final int count = getChildCount();
466 |
467 | for (int index = 0; index < count; ++index) {
468 | final View child = getChildAt(index);
469 | ObjectAnimator animator = mAnimators.getInitalAnimator(getContext());
470 | if( animator != null ){
471 | animator.setTarget(child);
472 | animator.start();
473 | }
474 | }
475 | }
476 |
477 | private void runShowActionAreaAnimation(View parent, View area) {
478 | area.setPivotY(0.f);
479 | area.setPivotX(parent.getWidth() / 2.f);
480 |
481 | area.setAlpha(0.5f);
482 | area.setRotationX(-90.f);
483 | area.animate().rotationX(0.f).alpha(1.f).setDuration(400);
484 | }
485 |
486 | private void handleViewSwipingOut(final View child, float deltaX, float deltaY) {
487 | ObjectAnimator animator = mAnimators.getSwipeOutAnimator(child, deltaX, deltaY);
488 | if( animator != null ){
489 | animator.addListener(new EndAnimationWrapper() {
490 | @Override
491 | public void onAnimationEnd(Animator animation) {
492 | removeView(child);
493 | notifyOnDismissEvent(child);
494 | }
495 | });
496 | } else {
497 | removeView(child);
498 | notifyOnDismissEvent(child);
499 | }
500 |
501 | if( animator != null ){
502 | animator.setTarget(child);
503 | animator.start();
504 | }
505 | }
506 |
507 | private void handleViewSwipingIn(final View child, float deltaX, float deltaY) {
508 | ObjectAnimator animator = mAnimators.getSwipeInAnimator(child, deltaX, deltaY);
509 | if( animator != null ){
510 | animator.addListener(new EndAnimationWrapper() {
511 | @Override
512 | public void onAnimationEnd(Animator animation) {
513 | child.setTranslationY(0.f);
514 | child.setTranslationX(0.f);
515 | }
516 | });
517 | } else {
518 | child.setTranslationY(0.f);
519 | child.setTranslationX(0.f);
520 | }
521 |
522 | if( animator != null ){
523 | animator.setTarget(child);
524 | animator.start();
525 | }
526 | }
527 |
528 | private void scrollToCard(String tag) {
529 |
530 |
531 | final int count = getChildCount();
532 | for (int index = 0; index < count; ++index) {
533 | View child = getChildAt(index);
534 |
535 | if (tag.equals(child.getTag())) {
536 |
537 | ViewParent parent = getParent();
538 | if( parent != null && parent instanceof ScrollView ){
539 | ((ScrollView)parent).smoothScrollTo(
540 | 0, child.getTop() - getPaddingTop() - child.getPaddingTop());
541 | }
542 | return;
543 | }
544 | }
545 | }
546 |
547 | public interface OnDissmissListener {
548 | public void onDismiss(String tag);
549 | }
550 |
551 | /**
552 | * Empty default AnimationListener
553 | */
554 | private abstract class EndAnimationWrapper implements Animator.AnimatorListener {
555 |
556 | @Override
557 | public void onAnimationStart(Animator animation) {
558 | }
559 |
560 | @Override
561 | public void onAnimationCancel(Animator animation) {
562 | }
563 |
564 | @Override
565 | public void onAnimationRepeat(Animator animation) {
566 | }
567 | }//end of inner class
568 | }
569 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/batchstepsensor/cardstream/CardStreamState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 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 |
18 | package com.example.android.batchstepsensor.cardstream;
19 |
20 | import java.util.HashSet;
21 |
22 | /**
23 | * A struct object that holds the state of a {@link CardStreamFragment}.
24 | */
25 | public class CardStreamState {
26 | protected Card[] visibleCards;
27 | protected Card[] hiddenCards;
28 | protected HashSet dismissibleCards;
29 | protected String shownTag;
30 |
31 | protected CardStreamState(Card[] visible, Card[] hidden, HashSet dismissible, String shownTag) {
32 | visibleCards = visible;
33 | hiddenCards = hidden;
34 | dismissibleCards = dismissible;
35 | this.shownTag = shownTag;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/batchstepsensor/cardstream/DefaultCardStreamAnimator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 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 |
18 | package com.example.android.batchstepsensor.cardstream;
19 |
20 | import android.animation.ObjectAnimator;
21 | import android.animation.PropertyValuesHolder;
22 | import android.annotation.TargetApi;
23 | import android.content.Context;
24 | import android.graphics.Point;
25 | import android.os.Build;
26 | import android.view.View;
27 | import android.view.WindowManager;
28 | import android.view.animation.BounceInterpolator;
29 |
30 | class DefaultCardStreamAnimator extends CardStreamAnimator {
31 |
32 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
33 | @Override
34 | public ObjectAnimator getDisappearingAnimator(Context context){
35 |
36 | ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(new Object(),
37 | PropertyValuesHolder.ofFloat("alpha", 1.f, 0.f),
38 | PropertyValuesHolder.ofFloat("scaleX", 1.f, 0.f),
39 | PropertyValuesHolder.ofFloat("scaleY", 1.f, 0.f),
40 | PropertyValuesHolder.ofFloat("rotation", 0.f, 270.f));
41 |
42 | animator.setDuration((long) (200 * mSpeedFactor));
43 | return animator;
44 | }
45 |
46 | @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
47 | @Override
48 | public ObjectAnimator getAppearingAnimator(Context context){
49 |
50 | final Point outPoint = new Point();
51 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
52 | wm.getDefaultDisplay().getSize(outPoint);
53 |
54 | ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(new Object(),
55 | PropertyValuesHolder.ofFloat("alpha", 0.f, 1.f),
56 | PropertyValuesHolder.ofFloat("translationY", outPoint.y / 2.f, 0.f),
57 | PropertyValuesHolder.ofFloat("rotation", -45.f, 0.f));
58 |
59 | animator.setDuration((long) (200 * mSpeedFactor));
60 | return animator;
61 | }
62 |
63 | @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
64 | @Override
65 | public ObjectAnimator getInitalAnimator(Context context){
66 |
67 | ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(new Object(),
68 | PropertyValuesHolder.ofFloat("alpha", 0.5f, 1.f),
69 | PropertyValuesHolder.ofFloat("rotation", 60.f, 0.f));
70 |
71 | animator.setDuration((long) (200 * mSpeedFactor));
72 | return animator;
73 | }
74 |
75 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
76 | @Override
77 | public ObjectAnimator getSwipeInAnimator(View view, float deltaX, float deltaY){
78 |
79 | float deltaXAbs = Math.abs(deltaX);
80 |
81 | float fractionCovered = 1.f - (deltaXAbs / view.getWidth());
82 | long duration = Math.abs((int) ((1 - fractionCovered) * 200 * mSpeedFactor));
83 |
84 | // Animate position and alpha of swiped item
85 |
86 | ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view,
87 | PropertyValuesHolder.ofFloat("alpha", 1.f),
88 | PropertyValuesHolder.ofFloat("translationX", 0.f),
89 | PropertyValuesHolder.ofFloat("rotationY", 0.f));
90 |
91 | animator.setDuration(duration).setInterpolator(new BounceInterpolator());
92 |
93 | return animator;
94 | }
95 |
96 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
97 | @Override
98 | public ObjectAnimator getSwipeOutAnimator(View view, float deltaX, float deltaY){
99 |
100 | float endX;
101 | float endRotationY;
102 |
103 | float deltaXAbs = Math.abs(deltaX);
104 |
105 | float fractionCovered = 1.f - (deltaXAbs / view.getWidth());
106 | long duration = Math.abs((int) ((1 - fractionCovered) * 200 * mSpeedFactor));
107 |
108 | endX = deltaX < 0 ? -view.getWidth() : view.getWidth();
109 | if (deltaX > 0)
110 | endRotationY = -15.f;
111 | else
112 | endRotationY = 15.f;
113 |
114 | // Animate position and alpha of swiped item
115 | return ObjectAnimator.ofPropertyValuesHolder(view,
116 | PropertyValuesHolder.ofFloat("alpha", 0.f),
117 | PropertyValuesHolder.ofFloat("translationX", endX),
118 | PropertyValuesHolder.ofFloat("rotationY", endRotationY)).setDuration(duration);
119 |
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/batchstepsensor/cardstream/OnCardClickListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 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 |
18 | package com.example.android.batchstepsensor.cardstream;
19 |
20 | public interface OnCardClickListener {
21 | public void onCardClick(int cardActionId, String cardTag);
22 | }
23 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/batchstepsensor/cardstream/StreamRetentionFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 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.cardstream;
18 |
19 | import android.os.Bundle;
20 | import android.support.v4.app.Fragment;
21 |
22 | public class StreamRetentionFragment extends Fragment {
23 |
24 | CardStreamState mState;
25 |
26 | @Override
27 | public void onActivityCreated(Bundle savedInstanceState) {
28 | super.onActivityCreated(savedInstanceState);
29 | setRetainInstance(true);
30 | }
31 |
32 | public void storeCardStream(CardStreamState state) {
33 | mState = state;
34 | }
35 |
36 | public CardStreamState getCardStream() {
37 | return mState;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/common/activities/SampleActivityBase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 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.common.activities;
18 |
19 | import android.os.Bundle;
20 | import android.support.v4.app.FragmentActivity;
21 |
22 | import com.example.android.common.logger.Log;
23 | import com.example.android.common.logger.LogWrapper;
24 |
25 | /**
26 | * Base launcher activity, to handle most of the common plumbing for samples.
27 | */
28 | public class SampleActivityBase extends FragmentActivity {
29 |
30 | public static final String TAG = "SampleActivityBase";
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | }
36 |
37 | @Override
38 | protected void onStart() {
39 | super.onStart();
40 | initializeLogging();
41 | }
42 |
43 | /** Set up targets to receive log data */
44 | public void initializeLogging() {
45 | // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
46 | // Wraps Android's native log framework
47 | LogWrapper logWrapper = new LogWrapper();
48 | Log.setLogNode(logWrapper);
49 |
50 | Log.i(TAG, "Ready");
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/common/logger/Log.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 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 | package com.example.android.common.logger;
17 |
18 | /**
19 | * Helper class for a list (or tree) of LoggerNodes.
20 | *
21 | * When this is set as the head of the list,
22 | * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
23 | * Most of the methods in this class server only to map a method call in Log to its equivalent
24 | * in LogNode.
25 | */
26 | public class Log {
27 | // Grabbing the native values from Android's native logging facilities,
28 | // to make for easy migration and interop.
29 | public static final int NONE = -1;
30 | public static final int VERBOSE = android.util.Log.VERBOSE;
31 | public static final int DEBUG = android.util.Log.DEBUG;
32 | public static final int INFO = android.util.Log.INFO;
33 | public static final int WARN = android.util.Log.WARN;
34 | public static final int ERROR = android.util.Log.ERROR;
35 | public static final int ASSERT = android.util.Log.ASSERT;
36 |
37 | // Stores the beginning of the LogNode topology.
38 | private static LogNode mLogNode;
39 |
40 | /**
41 | * Returns the next LogNode in the linked list.
42 | */
43 | public static LogNode getLogNode() {
44 | return mLogNode;
45 | }
46 |
47 | /**
48 | * Sets the LogNode data will be sent to.
49 | */
50 | public static void setLogNode(LogNode node) {
51 | mLogNode = node;
52 | }
53 |
54 | /**
55 | * Instructs the LogNode to print the log data provided. Other LogNodes can
56 | * be chained to the end of the LogNode as desired.
57 | *
58 | * @param priority Log level of the data being logged. Verbose, Error, etc.
59 | * @param tag Tag for for the log data. Can be used to organize log statements.
60 | * @param msg The actual message to be logged.
61 | * @param tr If an exception was thrown, this can be sent along for the logging facilities
62 | * to extract and print useful information.
63 | */
64 | public static void println(int priority, String tag, String msg, Throwable tr) {
65 | if (mLogNode != null) {
66 | mLogNode.println(priority, tag, msg, tr);
67 | }
68 | }
69 |
70 | /**
71 | * Instructs the LogNode to print the log data provided. Other LogNodes can
72 | * be chained to the end of the LogNode as desired.
73 | *
74 | * @param priority Log level of the data being logged. Verbose, Error, etc.
75 | * @param tag Tag for for the log data. Can be used to organize log statements.
76 | * @param msg The actual message to be logged. The actual message to be logged.
77 | */
78 | public static void println(int priority, String tag, String msg) {
79 | println(priority, tag, msg, null);
80 | }
81 |
82 | /**
83 | * Prints a message at VERBOSE priority.
84 | *
85 | * @param tag Tag for for the log data. Can be used to organize log statements.
86 | * @param msg The actual message to be logged.
87 | * @param tr If an exception was thrown, this can be sent along for the logging facilities
88 | * to extract and print useful information.
89 | */
90 | public static void v(String tag, String msg, Throwable tr) {
91 | println(VERBOSE, tag, msg, tr);
92 | }
93 |
94 | /**
95 | * Prints a message at VERBOSE priority.
96 | *
97 | * @param tag Tag for for the log data. Can be used to organize log statements.
98 | * @param msg The actual message to be logged.
99 | */
100 | public static void v(String tag, String msg) {
101 | v(tag, msg, null);
102 | }
103 |
104 |
105 | /**
106 | * Prints a message at DEBUG priority.
107 | *
108 | * @param tag Tag for for the log data. Can be used to organize log statements.
109 | * @param msg The actual message to be logged.
110 | * @param tr If an exception was thrown, this can be sent along for the logging facilities
111 | * to extract and print useful information.
112 | */
113 | public static void d(String tag, String msg, Throwable tr) {
114 | println(DEBUG, tag, msg, tr);
115 | }
116 |
117 | /**
118 | * Prints a message at DEBUG priority.
119 | *
120 | * @param tag Tag for for the log data. Can be used to organize log statements.
121 | * @param msg The actual message to be logged.
122 | */
123 | public static void d(String tag, String msg) {
124 | d(tag, msg, null);
125 | }
126 |
127 | /**
128 | * Prints a message at INFO priority.
129 | *
130 | * @param tag Tag for for the log data. Can be used to organize log statements.
131 | * @param msg The actual message to be logged.
132 | * @param tr If an exception was thrown, this can be sent along for the logging facilities
133 | * to extract and print useful information.
134 | */
135 | public static void i(String tag, String msg, Throwable tr) {
136 | println(INFO, tag, msg, tr);
137 | }
138 |
139 | /**
140 | * Prints a message at INFO priority.
141 | *
142 | * @param tag Tag for for the log data. Can be used to organize log statements.
143 | * @param msg The actual message to be logged.
144 | */
145 | public static void i(String tag, String msg) {
146 | i(tag, msg, null);
147 | }
148 |
149 | /**
150 | * Prints a message at WARN priority.
151 | *
152 | * @param tag Tag for for the log data. Can be used to organize log statements.
153 | * @param msg The actual message to be logged.
154 | * @param tr If an exception was thrown, this can be sent along for the logging facilities
155 | * to extract and print useful information.
156 | */
157 | public static void w(String tag, String msg, Throwable tr) {
158 | println(WARN, tag, msg, tr);
159 | }
160 |
161 | /**
162 | * Prints a message at WARN priority.
163 | *
164 | * @param tag Tag for for the log data. Can be used to organize log statements.
165 | * @param msg The actual message to be logged.
166 | */
167 | public static void w(String tag, String msg) {
168 | w(tag, msg, null);
169 | }
170 |
171 | /**
172 | * Prints a message at WARN priority.
173 | *
174 | * @param tag Tag for for the log data. Can be used to organize log statements.
175 | * @param tr If an exception was thrown, this can be sent along for the logging facilities
176 | * to extract and print useful information.
177 | */
178 | public static void w(String tag, Throwable tr) {
179 | w(tag, null, tr);
180 | }
181 |
182 | /**
183 | * Prints a message at ERROR priority.
184 | *
185 | * @param tag Tag for for the log data. Can be used to organize log statements.
186 | * @param msg The actual message to be logged.
187 | * @param tr If an exception was thrown, this can be sent along for the logging facilities
188 | * to extract and print useful information.
189 | */
190 | public static void e(String tag, String msg, Throwable tr) {
191 | println(ERROR, tag, msg, tr);
192 | }
193 |
194 | /**
195 | * Prints a message at ERROR priority.
196 | *
197 | * @param tag Tag for for the log data. Can be used to organize log statements.
198 | * @param msg The actual message to be logged.
199 | */
200 | public static void e(String tag, String msg) {
201 | e(tag, msg, null);
202 | }
203 |
204 | /**
205 | * Prints a message at ASSERT priority.
206 | *
207 | * @param tag Tag for for the log data. Can be used to organize log statements.
208 | * @param msg The actual message to be logged.
209 | * @param tr If an exception was thrown, this can be sent along for the logging facilities
210 | * to extract and print useful information.
211 | */
212 | public static void wtf(String tag, String msg, Throwable tr) {
213 | println(ASSERT, tag, msg, tr);
214 | }
215 |
216 | /**
217 | * Prints a message at ASSERT priority.
218 | *
219 | * @param tag Tag for for the log data. Can be used to organize log statements.
220 | * @param msg The actual message to be logged.
221 | */
222 | public static void wtf(String tag, String msg) {
223 | wtf(tag, msg, null);
224 | }
225 |
226 | /**
227 | * Prints a message at ASSERT priority.
228 | *
229 | * @param tag Tag for for the log data. Can be used to organize log statements.
230 | * @param tr If an exception was thrown, this can be sent along for the logging facilities
231 | * to extract and print useful information.
232 | */
233 | public static void wtf(String tag, Throwable tr) {
234 | wtf(tag, null, tr);
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/common/logger/LogFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 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 | * Copyright 2013 The Android Open Source Project
18 | *
19 | * Licensed under the Apache License, Version 2.0 (the "License");
20 | * you may not use this file except in compliance with the License.
21 | * You may obtain a copy of the License at
22 | *
23 | * http://www.apache.org/licenses/LICENSE-2.0
24 | *
25 | * Unless required by applicable law or agreed to in writing, software
26 | * distributed under the License is distributed on an "AS IS" BASIS,
27 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28 | * See the License for the specific language governing permissions and
29 | * limitations under the License.
30 | */
31 |
32 | package com.example.android.common.logger;
33 |
34 | import android.graphics.Typeface;
35 | import android.os.Bundle;
36 | import android.support.v4.app.Fragment;
37 | import android.text.Editable;
38 | import android.text.TextWatcher;
39 | import android.view.Gravity;
40 | import android.view.LayoutInflater;
41 | import android.view.View;
42 | import android.view.ViewGroup;
43 | import android.widget.ScrollView;
44 |
45 | /**
46 | * Simple fraggment which contains a LogView and uses is to output log data it receives
47 | * through the LogNode interface.
48 | */
49 | public class LogFragment extends Fragment {
50 |
51 | private LogView mLogView;
52 | private ScrollView mScrollView;
53 |
54 | public LogFragment() {}
55 |
56 | public View inflateViews() {
57 | mScrollView = new ScrollView(getActivity());
58 | ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
59 | ViewGroup.LayoutParams.MATCH_PARENT,
60 | ViewGroup.LayoutParams.MATCH_PARENT);
61 | mScrollView.setLayoutParams(scrollParams);
62 |
63 | mLogView = new LogView(getActivity());
64 | ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
65 | logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
66 | mLogView.setLayoutParams(logParams);
67 | mLogView.setClickable(true);
68 | mLogView.setFocusable(true);
69 | mLogView.setTypeface(Typeface.MONOSPACE);
70 |
71 | // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
72 | int paddingDips = 16;
73 | double scale = getResources().getDisplayMetrics().density;
74 | int paddingPixels = (int) ((paddingDips * (scale)) + .5);
75 | mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
76 | mLogView.setCompoundDrawablePadding(paddingPixels);
77 |
78 | mLogView.setGravity(Gravity.BOTTOM);
79 | mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
80 |
81 | mScrollView.addView(mLogView);
82 | return mScrollView;
83 | }
84 |
85 | @Override
86 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
87 | Bundle savedInstanceState) {
88 |
89 | View result = inflateViews();
90 |
91 | mLogView.addTextChangedListener(new TextWatcher() {
92 | @Override
93 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
94 |
95 | @Override
96 | public void onTextChanged(CharSequence s, int start, int before, int count) {}
97 |
98 | @Override
99 | public void afterTextChanged(Editable s) {
100 | mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
101 | }
102 | });
103 | return result;
104 | }
105 |
106 | public LogView getLogView() {
107 | return mLogView;
108 | }
109 | }
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/common/logger/LogNode.java:
--------------------------------------------------------------------------------
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 | package com.example.android.common.logger;
17 |
18 | /**
19 | * Basic interface for a logging system that can output to one or more targets.
20 | * Note that in addition to classes that will output these logs in some format,
21 | * one can also implement this interface over a filter and insert that in the chain,
22 | * such that no targets further down see certain data, or see manipulated forms of the data.
23 | * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
24 | * it received to HTML and sent it along to the next node in the chain, without printing it
25 | * anywhere.
26 | */
27 | public interface LogNode {
28 |
29 | /**
30 | * Instructs first LogNode in the list to print the log data provided.
31 | * @param priority Log level of the data being logged. Verbose, Error, etc.
32 | * @param tag Tag for for the log data. Can be used to organize log statements.
33 | * @param msg The actual message to be logged. The actual message to be logged.
34 | * @param tr If an exception was thrown, this can be sent along for the logging facilities
35 | * to extract and print useful information.
36 | */
37 | public void println(int priority, String tag, String msg, Throwable tr);
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/common/logger/LogView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 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 | package com.example.android.common.logger;
17 |
18 | import android.app.Activity;
19 | import android.content.Context;
20 | import android.util.*;
21 | import android.widget.TextView;
22 |
23 | /** Simple TextView which is used to output log data received through the LogNode interface.
24 | */
25 | public class LogView extends TextView implements LogNode {
26 |
27 | public LogView(Context context) {
28 | super(context);
29 | }
30 |
31 | public LogView(Context context, AttributeSet attrs) {
32 | super(context, attrs);
33 | }
34 |
35 | public LogView(Context context, AttributeSet attrs, int defStyle) {
36 | super(context, attrs, defStyle);
37 | }
38 |
39 | /**
40 | * Formats the log data and prints it out to the LogView.
41 | * @param priority Log level of the data being logged. Verbose, Error, etc.
42 | * @param tag Tag for for the log data. Can be used to organize log statements.
43 | * @param msg The actual message to be logged. The actual message to be logged.
44 | * @param tr If an exception was thrown, this can be sent along for the logging facilities
45 | * to extract and print useful information.
46 | */
47 | @Override
48 | public void println(int priority, String tag, String msg, Throwable tr) {
49 |
50 |
51 | String priorityStr = null;
52 |
53 | // For the purposes of this View, we want to print the priority as readable text.
54 | switch(priority) {
55 | case android.util.Log.VERBOSE:
56 | priorityStr = "VERBOSE";
57 | break;
58 | case android.util.Log.DEBUG:
59 | priorityStr = "DEBUG";
60 | break;
61 | case android.util.Log.INFO:
62 | priorityStr = "INFO";
63 | break;
64 | case android.util.Log.WARN:
65 | priorityStr = "WARN";
66 | break;
67 | case android.util.Log.ERROR:
68 | priorityStr = "ERROR";
69 | break;
70 | case android.util.Log.ASSERT:
71 | priorityStr = "ASSERT";
72 | break;
73 | default:
74 | break;
75 | }
76 |
77 | // Handily, the Log class has a facility for converting a stack trace into a usable string.
78 | String exceptionStr = null;
79 | if (tr != null) {
80 | exceptionStr = android.util.Log.getStackTraceString(tr);
81 | }
82 |
83 | // Take the priority, tag, message, and exception, and concatenate as necessary
84 | // into one usable line of text.
85 | final StringBuilder outputBuilder = new StringBuilder();
86 |
87 | String delimiter = "\t";
88 | appendIfNotNull(outputBuilder, priorityStr, delimiter);
89 | appendIfNotNull(outputBuilder, tag, delimiter);
90 | appendIfNotNull(outputBuilder, msg, delimiter);
91 | appendIfNotNull(outputBuilder, exceptionStr, delimiter);
92 |
93 | // In case this was originally called from an AsyncTask or some other off-UI thread,
94 | // make sure the update occurs within the UI thread.
95 | ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
96 | @Override
97 | public void run() {
98 | // Display the text we just generated within the LogView.
99 | appendToLog(outputBuilder.toString());
100 | }
101 | })));
102 |
103 | if (mNext != null) {
104 | mNext.println(priority, tag, msg, tr);
105 | }
106 | }
107 |
108 | public LogNode getNext() {
109 | return mNext;
110 | }
111 |
112 | public void setNext(LogNode node) {
113 | mNext = node;
114 | }
115 |
116 | /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
117 | * the logger takes so many arguments that might be null, this method helps cut out some of the
118 | * agonizing tedium of writing the same 3 lines over and over.
119 | * @param source StringBuilder containing the text to append to.
120 | * @param addStr The String to append
121 | * @param delimiter The String to separate the source and appended strings. A tab or comma,
122 | * for instance.
123 | * @return The fully concatenated String as a StringBuilder
124 | */
125 | private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
126 | if (addStr != null) {
127 | if (addStr.length() == 0) {
128 | delimiter = "";
129 | }
130 |
131 | return source.append(addStr).append(delimiter);
132 | }
133 | return source;
134 | }
135 |
136 | // The next LogNode in the chain.
137 | LogNode mNext;
138 |
139 | /** Outputs the string as a new line of log data in the LogView. */
140 | public void appendToLog(String s) {
141 | append("\n" + s);
142 | }
143 |
144 |
145 | }
146 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/common/logger/LogWrapper.java:
--------------------------------------------------------------------------------
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 | package com.example.android.common.logger;
17 |
18 | import android.util.Log;
19 |
20 | /**
21 | * Helper class which wraps Android's native Log utility in the Logger interface. This way
22 | * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
23 | */
24 | public class LogWrapper implements LogNode {
25 |
26 | // For piping: The next node to receive Log data after this one has done its work.
27 | private LogNode mNext;
28 |
29 | /**
30 | * Returns the next LogNode in the linked list.
31 | */
32 | public LogNode getNext() {
33 | return mNext;
34 | }
35 |
36 | /**
37 | * Sets the LogNode data will be sent to..
38 | */
39 | public void setNext(LogNode node) {
40 | mNext = node;
41 | }
42 |
43 | /**
44 | * Prints data out to the console using Android's native log mechanism.
45 | * @param priority Log level of the data being logged. Verbose, Error, etc.
46 | * @param tag Tag for for the log data. Can be used to organize log statements.
47 | * @param msg The actual message to be logged. The actual message to be logged.
48 | * @param tr If an exception was thrown, this can be sent along for the logging facilities
49 | * to extract and print useful information.
50 | */
51 | @Override
52 | public void println(int priority, String tag, String msg, Throwable tr) {
53 | // There actually are log methods that don't take a msg parameter. For now,
54 | // if that's the case, just convert null to the empty string and move on.
55 | String useMsg = msg;
56 | if (useMsg == null) {
57 | useMsg = "";
58 | }
59 |
60 | // If an exeption was provided, convert that exception to a usable string and attach
61 | // it to the end of the msg method.
62 | if (tr != null) {
63 | msg += "\n" + Log.getStackTraceString(tr);
64 | }
65 |
66 | // This is functionally identical to Log.x(tag, useMsg);
67 | // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
68 | Log.println(priority, tag, useMsg);
69 |
70 | // If this isn't the last node in the chain, move things along.
71 | if (mNext != null) {
72 | mNext.println(priority, tag, msg, tr);
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Application/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 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 | package com.example.android.common.logger;
17 |
18 | /**
19 | * Simple {@link LogNode} filter, removes everything except the message.
20 | * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
21 | * just easy-to-read message updates as they're happening.
22 | */
23 | public class MessageOnlyLogFilter implements LogNode {
24 |
25 | LogNode mNext;
26 |
27 | /**
28 | * Takes the "next" LogNode as a parameter, to simplify chaining.
29 | *
30 | * @param next The next LogNode in the pipeline.
31 | */
32 | public MessageOnlyLogFilter(LogNode next) {
33 | mNext = next;
34 | }
35 |
36 | public MessageOnlyLogFilter() {
37 | }
38 |
39 | @Override
40 | public void println(int priority, String tag, String msg, Throwable tr) {
41 | if (mNext != null) {
42 | getNext().println(Log.NONE, null, msg, null);
43 | }
44 | }
45 |
46 | /**
47 | * Returns the next LogNode in the chain.
48 | */
49 | public LogNode getNext() {
50 | return mNext;
51 | }
52 |
53 | /**
54 | * Sets the LogNode data will be sent to..
55 | */
56 | public void setNext(LogNode node) {
57 | mNext = node;
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-hdpi/ic_action_cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-hdpi/ic_action_cancel.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-hdpi/tile.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-hdpi/tile.9.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-mdpi/ic_action_cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-mdpi/ic_action_cancel.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-v21/card_action_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-v21/card_action_bg_negative.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-v21/card_action_bg_positive.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-xhdpi/card_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-xhdpi/card_bg.9.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-xhdpi/ic_cardaction_negative.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-xhdpi/ic_cardaction_negative.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-xhdpi/ic_cardaction_negative_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-xhdpi/ic_cardaction_negative_pressed.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-xhdpi/ic_cardaction_neutral.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-xhdpi/ic_cardaction_neutral.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-xhdpi/ic_cardaction_neutral_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-xhdpi/ic_cardaction_neutral_pressed.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-xhdpi/ic_cardaction_positive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-xhdpi/ic_cardaction_positive.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-xhdpi/ic_cardaction_positive_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-xhdpi/ic_cardaction_positive_pressed.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-xxhdpi/ic_action_cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-xxhdpi/ic_action_cancel.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Application/src/main/res/drawable/card_action_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Application/src/main/res/drawable/card_action_bg_negative.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Application/src/main/res/drawable/card_action_bg_positive.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Application/src/main/res/drawable/card_action_icon_negative.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Application/src/main/res/drawable/card_action_icon_neutral.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Application/src/main/res/drawable/card_action_icon_positive.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Application/src/main/res/drawable/card_action_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Application/src/main/res/drawable/card_action_text_negative.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Application/src/main/res/drawable/card_action_text_positive.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Application/src/main/res/drawable/card_overlay_focused.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
--------------------------------------------------------------------------------
/Application/src/main/res/drawable/card_separator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Application/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
27 |
--------------------------------------------------------------------------------
/Application/src/main/res/layout/card.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
24 |
25 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
51 |
52 |
58 |
59 |
60 |
61 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/Application/src/main/res/layout/card_button_negative.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
--------------------------------------------------------------------------------
/Application/src/main/res/layout/card_button_neutral.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
24 |
--------------------------------------------------------------------------------
/Application/src/main/res/layout/card_button_positive.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
24 |
--------------------------------------------------------------------------------
/Application/src/main/res/layout/card_button_seperator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
--------------------------------------------------------------------------------
/Application/src/main/res/layout/card_progress.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
15 |
16 |
22 |
23 |
--------------------------------------------------------------------------------
/Application/src/main/res/layout/cardstream.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
22 |
23 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Application/src/main/res/values-sw600dp/template-dimens.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 | @dimen/margin_huge
22 | @dimen/margin_medium
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Application/src/main/res/values-sw600dp/template-styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Application/src/main/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 128dp
5 |
6 |
--------------------------------------------------------------------------------
/Application/src/main/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Application/src/main/res/values-v11/template-styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Application/src/main/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Application/src/main/res/values-v16/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
11 |
--------------------------------------------------------------------------------
/Application/src/main/res/values-v21/base-colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Application/src/main/res/values-v21/base-template-styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Application/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Application/src/main/res/values/base-strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | BatchStepSensor
20 |
21 | This sample demonstrates the use of the two step sensors (step detector and counter) and
25 | sensor batching.
26 | It shows how to register a SensorEventListener with and without
27 | batching and shows how these events are received.
28 | The Step Detector sensor fires an
29 | event when a step is detected, while the step counter returns the total number of
30 | steps since a listener was first registered for this sensor.
31 | Both sensors only count steps while a listener is registered. This sample only covers the
32 | basic case, where a listener is only registered while the app is running. Likewise,
33 | batched sensors can be used in the background (when the CPU is suspended), which
34 | requires manually flushing the sensor event queue before it overflows, which is not
35 | covered in this sample.
36 |
37 |
38 | ]]>
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Application/src/main/res/values/color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | @android:color/white
5 |
6 | #444
7 |
8 | #DDD
9 | #F4F4F4
10 |
11 |
12 | #FFE3F4FC
13 | #FF47B4EA
14 | #CC47B4EA
15 |
16 |
17 | #FFFBCBCA
18 | #FFF64940
19 | #CCF64940
20 |
21 |
22 | #FFE4F0AF
23 | #FFA0CC00
24 | #CCA0CC00
25 |
26 |
--------------------------------------------------------------------------------
/Application/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 14sp
4 | 24sp
5 |
6 | 15dp
7 | 10dp
8 |
9 | 3dp
10 | 8dp
11 |
12 | 90dp
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Application/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Application/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | Introduction
20 |
21 | Background sensor batching
22 | Batching allows the sensor to report sensor events at
23 | a specified frequency.\n\nThe system delays calls to the SensorEventListener and deliver
24 | them in intervals, based on the maximum report latency specified when the listener is
25 | registered. Note that this only means that the call to onSensorChanged() is delayed, the
26 | total number of calls is identical as if no batching was used. Sensors only deliver events
27 | while the CPU is awake. If the CPU is asleep and a batched sensor event listener is still
28 | registered, the sensor will continue to collect events until it runs out of memory and
29 | overwrites old values. This use case is not covered by this sample. (The sensor event queue
30 | should be flushed using a scheduled background thread.) \n\nIn this sample app data is only
31 | collected while the app is running and the CPU is awake. In this case the sensor will
32 | deliver events before the queue fills up.
33 |
34 |
35 | The age of a sensor event describes the delay between
36 | when it was recorded by the sensor until it was delivered to the SensorEventListener.
37 |
38 |
39 | Register step detector sensor
40 | Register a listener for the STEP DETECTOR
41 | sensor.\n\nThis sensor delivers an event when the user takes a step. One event is received
42 | per step.
43 |
44 |
45 | Register step counter sensor
46 | Register a listener for the STEP COUNTER
47 | sensor.\n\nThis sensor triggers events when a step is detected, but applies algorithms to
48 | filter out false positives. Events from this sensor have higher latency than the step
49 | detector and contain the total number of steps taken since the sensor was first registered.
50 |
51 |
52 | No batching (delay=0)
53 | 5s batching (delay=5000ms)
54 | 10s batching (delay=10000ms)
55 |
56 | Total Steps: %1$d
57 | Step Counter
58 | Step Detector
59 | Sensor: %1$s\nMax sensor event delay: %2$,d \u00B5s\nAge of
60 | events in s:\n%3$s
61 |
62 |
63 | Error
64 | This sample requires at least Android KitKat (4.4) and a device
65 | with the step sensor.\n\nThis device does not appear to meet these requirements, as an
66 | alternative you may want to consider using the gyro sensor and implement your own step
67 | recognition as a fallback.
68 |
69 | The listener has been registered, but batch mode could not be
70 | enabled.\n\nIt is likely that it is not supported by this device.\n\nSensor events will be
71 | delivered in continuous mode.
72 |
73 |
74 | Do not show again
75 |
--------------------------------------------------------------------------------
/Application/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
15 |
16 |
19 |
20 |
25 |
26 |
30 |
31 |
32 |
36 |
37 |
39 |
40 |
45 |
46 |
48 |
49 |
50 |
58 |
59 |
64 |
65 |
70 |
71 |
76 |
77 |
78 |
85 |
86 |
91 |
92 |
--------------------------------------------------------------------------------
/Application/src/main/res/values/template-dimens.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 | 4dp
22 | 8dp
23 | 16dp
24 | 32dp
25 | 64dp
26 |
27 |
28 |
29 | @dimen/margin_medium
30 | @dimen/margin_medium
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Application/src/main/res/values/template-styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
34 |
35 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/CONTRIB.md:
--------------------------------------------------------------------------------
1 | # How to become a contributor and submit your own code
2 |
3 | ## Contributor License Agreements
4 |
5 | We'd love to accept your sample apps and patches! Before we can take them, we
6 | have to jump a couple of legal hurdles.
7 |
8 | Please fill out either the individual or corporate Contributor License Agreement (CLA).
9 |
10 | * If you are an individual writing original source code and you're sure you
11 | own the intellectual property, then you'll need to sign an [individual CLA]
12 | (https://developers.google.com/open-source/cla/individual).
13 | * If you work for a company that wants to allow you to contribute your work,
14 | then you'll need to sign a [corporate CLA]
15 | (https://developers.google.com/open-source/cla/corporate).
16 |
17 | Follow either of the two links above to access the appropriate CLA and
18 | instructions for how to sign and return it. Once we receive it, we'll be able to
19 | accept your pull requests.
20 |
21 | ## Contributing A Patch
22 |
23 | 1. Submit an issue describing your proposed change to the repo in question.
24 | 1. The repo owner will respond to your issue promptly.
25 | 1. If your proposed change is accepted, and you haven't already done so, sign a
26 | Contributor License Agreement (see details above).
27 | 1. Fork the desired repo, develop and test your code changes.
28 | 1. Ensure that your code adheres to the existing style in the sample to which
29 | you are contributing. Refer to the
30 | [Android Code Style Guide]
31 | (https://source.android.com/source/code-style.html) for the
32 | recommended coding standards for this organization.
33 | 1. Ensure that your code has an appropriate set of unit tests which all pass.
34 | 1. Submit a pull request.
35 |
36 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to become a contributor and submit your own code
2 |
3 | ## Contributor License Agreements
4 |
5 | We'd love to accept your sample apps and patches! Before we can take them, we
6 | have to jump a couple of legal hurdles.
7 |
8 | Please fill out either the individual or corporate Contributor License Agreement (CLA).
9 |
10 | * If you are an individual writing original source code and you're sure you
11 | own the intellectual property, then you'll need to sign an [individual CLA]
12 | (https://cla.developers.google.com).
13 | * If you work for a company that wants to allow you to contribute your work,
14 | then you'll need to sign a [corporate CLA]
15 | (https://cla.developers.google.com).
16 |
17 | Follow either of the two links above to access the appropriate CLA and
18 | instructions for how to sign and return it. Once we receive it, we'll be able to
19 | accept your pull requests.
20 |
21 | ## Contributing A Patch
22 |
23 | 1. Submit an issue describing your proposed change to the repo in question.
24 | 1. The repo owner will respond to your issue promptly.
25 | 1. If your proposed change is accepted, and you haven't already done so, sign a
26 | Contributor License Agreement (see details above).
27 | 1. Fork the desired repo, develop and test your code changes.
28 | 1. Ensure that your code adheres to the existing style in the sample to which
29 | you are contributing. Refer to the
30 | [Android Code Style Guide]
31 | (https://source.android.com/source/code-style.html) for the
32 | recommended coding standards for this organization.
33 | 1. Ensure that your code has an appropriate set of unit tests which all pass.
34 | 1. Submit a pull request.
35 |
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | --------------
3 |
4 | Version 2.0, January 2004
5 | http://www.apache.org/licenses/
6 |
7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8 |
9 | 1. Definitions.
10 |
11 | "License" shall mean the terms and conditions for use, reproduction,
12 | and distribution as defined by Sections 1 through 9 of this document.
13 |
14 | "Licensor" shall mean the copyright owner or entity authorized by
15 | the copyright owner that is granting the License.
16 |
17 | "Legal Entity" shall mean the union of the acting entity and all
18 | other entities that control, are controlled by, or are under common
19 | control with that entity. For the purposes of this definition,
20 | "control" means (i) the power, direct or indirect, to cause the
21 | direction or management of such entity, whether by contract or
22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
23 | outstanding shares, or (iii) beneficial ownership of such entity.
24 |
25 | "You" (or "Your") shall mean an individual or Legal Entity
26 | exercising permissions granted by this License.
27 |
28 | "Source" form shall mean the preferred form for making modifications,
29 | including but not limited to software source code, documentation
30 | source, and configuration files.
31 |
32 | "Object" form shall mean any form resulting from mechanical
33 | transformation or translation of a Source form, including but
34 | not limited to compiled object code, generated documentation,
35 | and conversions to other media types.
36 |
37 | "Work" shall mean the work of authorship, whether in Source or
38 | Object form, made available under the License, as indicated by a
39 | copyright notice that is included in or attached to the work
40 | (an example is provided in the Appendix below).
41 |
42 | "Derivative Works" shall mean any work, whether in Source or Object
43 | form, that is based on (or derived from) the Work and for which the
44 | editorial revisions, annotations, elaborations, or other modifications
45 | represent, as a whole, an original work of authorship. For the purposes
46 | of this License, Derivative Works shall not include works that remain
47 | separable from, or merely link (or bind by name) to the interfaces of,
48 | the Work and Derivative Works thereof.
49 |
50 | "Contribution" shall mean any work of authorship, including
51 | the original version of the Work and any modifications or additions
52 | to that Work or Derivative Works thereof, that is intentionally
53 | submitted to Licensor for inclusion in the Work by the copyright owner
54 | or by an individual or Legal Entity authorized to submit on behalf of
55 | the copyright owner. For the purposes of this definition, "submitted"
56 | means any form of electronic, verbal, or written communication sent
57 | to the Licensor or its representatives, including but not limited to
58 | communication on electronic mailing lists, source code control systems,
59 | and issue tracking systems that are managed by, or on behalf of, the
60 | Licensor for the purpose of discussing and improving the Work, but
61 | excluding communication that is conspicuously marked or otherwise
62 | designated in writing by the copyright owner as "Not a Contribution."
63 |
64 | "Contributor" shall mean Licensor and any individual or Legal Entity
65 | on behalf of whom a Contribution has been received by Licensor and
66 | subsequently incorporated within the Work.
67 |
68 | 2. Grant of Copyright License. Subject to the terms and conditions of
69 | this License, each Contributor hereby grants to You a perpetual,
70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
71 | copyright license to reproduce, prepare Derivative Works of,
72 | publicly display, publicly perform, sublicense, and distribute the
73 | Work and such Derivative Works in Source or Object form.
74 |
75 | 3. Grant of Patent License. Subject to the terms and conditions of
76 | this License, each Contributor hereby grants to You a perpetual,
77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
78 | (except as stated in this section) patent license to make, have made,
79 | use, offer to sell, sell, import, and otherwise transfer the Work,
80 | where such license applies only to those patent claims licensable
81 | by such Contributor that are necessarily infringed by their
82 | Contribution(s) alone or by combination of their Contribution(s)
83 | with the Work to which such Contribution(s) was submitted. If You
84 | institute patent litigation against any entity (including a
85 | cross-claim or counterclaim in a lawsuit) alleging that the Work
86 | or a Contribution incorporated within the Work constitutes direct
87 | or contributory patent infringement, then any patent licenses
88 | granted to You under this License for that Work shall terminate
89 | as of the date such litigation is filed.
90 |
91 | 4. Redistribution. You may reproduce and distribute copies of the
92 | Work or Derivative Works thereof in any medium, with or without
93 | modifications, and in Source or Object form, provided that You
94 | meet the following conditions:
95 |
96 | (a) You must give any other recipients of the Work or
97 | Derivative Works a copy of this License; and
98 |
99 | (b) You must cause any modified files to carry prominent notices
100 | stating that You changed the files; and
101 |
102 | (c) You must retain, in the Source form of any Derivative Works
103 | that You distribute, all copyright, patent, trademark, and
104 | attribution notices from the Source form of the Work,
105 | excluding those notices that do not pertain to any part of
106 | the Derivative Works; and
107 |
108 | (d) If the Work includes a "NOTICE" text file as part of its
109 | distribution, then any Derivative Works that You distribute must
110 | include a readable copy of the attribution notices contained
111 | within such NOTICE file, excluding those notices that do not
112 | pertain to any part of the Derivative Works, in at least one
113 | of the following places: within a NOTICE text file distributed
114 | as part of the Derivative Works; within the Source form or
115 | documentation, if provided along with the Derivative Works; or,
116 | within a display generated by the Derivative Works, if and
117 | wherever such third-party notices normally appear. The contents
118 | of the NOTICE file are for informational purposes only and
119 | do not modify the License. You may add Your own attribution
120 | notices within Derivative Works that You distribute, alongside
121 | or as an addendum to the NOTICE text from the Work, provided
122 | that such additional attribution notices cannot be construed
123 | as modifying the License.
124 |
125 | You may add Your own copyright statement to Your modifications and
126 | may provide additional or different license terms and conditions
127 | for use, reproduction, or distribution of Your modifications, or
128 | for any such Derivative Works as a whole, provided Your use,
129 | reproduction, and distribution of the Work otherwise complies with
130 | the conditions stated in this License.
131 |
132 | 5. Submission of Contributions. Unless You explicitly state otherwise,
133 | any Contribution intentionally submitted for inclusion in the Work
134 | by You to the Licensor shall be under the terms and conditions of
135 | this License, without any additional terms or conditions.
136 | Notwithstanding the above, nothing herein shall supersede or modify
137 | the terms of any separate license agreement you may have executed
138 | with Licensor regarding such Contributions.
139 |
140 | 6. Trademarks. This License does not grant permission to use the trade
141 | names, trademarks, service marks, or product names of the Licensor,
142 | except as required for reasonable and customary use in describing the
143 | origin of the Work and reproducing the content of the NOTICE file.
144 |
145 | 7. Disclaimer of Warranty. Unless required by applicable law or
146 | agreed to in writing, Licensor provides the Work (and each
147 | Contributor provides its Contributions) on an "AS IS" BASIS,
148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
149 | implied, including, without limitation, any warranties or conditions
150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
151 | PARTICULAR PURPOSE. You are solely responsible for determining the
152 | appropriateness of using or redistributing the Work and assume any
153 | risks associated with Your exercise of permissions under this License.
154 |
155 | 8. Limitation of Liability. In no event and under no legal theory,
156 | whether in tort (including negligence), contract, or otherwise,
157 | unless required by applicable law (such as deliberate and grossly
158 | negligent acts) or agreed to in writing, shall any Contributor be
159 | liable to You for damages, including any direct, indirect, special,
160 | incidental, or consequential damages of any character arising as a
161 | result of this License or out of the use or inability to use the
162 | Work (including but not limited to damages for loss of goodwill,
163 | work stoppage, computer failure or malfunction, or any and all
164 | other commercial damages or losses), even if such Contributor
165 | has been advised of the possibility of such damages.
166 |
167 | 9. Accepting Warranty or Additional Liability. While redistributing
168 | the Work or Derivative Works thereof, You may choose to offer,
169 | and charge a fee for, acceptance of support, warranty, indemnity,
170 | or other liability obligations and/or rights consistent with this
171 | License. However, in accepting such obligations, You may act only
172 | on Your own behalf and on Your sole responsibility, not on behalf
173 | of any other Contributor, and only if You agree to indemnify,
174 | defend, and hold each Contributor harmless for any liability
175 | incurred by, or claims asserted against, such Contributor by reason
176 | of your accepting any such warranty or additional liability.
177 |
178 | END OF TERMS AND CONDITIONS
179 |
180 | APPENDIX: How to apply the Apache License to your work.
181 |
182 | To apply the Apache License to your work, attach the following
183 | boilerplate notice, with the fields enclosed by brackets "{}"
184 | replaced with your own identifying information. (Don't include
185 | the brackets!) The text should be enclosed in the appropriate
186 | comment syntax for the file format. We also recommend that a
187 | file or class name and description of purpose be included on the
188 | same "printed page" as the copyright notice for easier
189 | identification within third-party archives.
190 |
191 | Copyright {yyyy} {name of copyright owner}
192 |
193 | Licensed under the Apache License, Version 2.0 (the "License");
194 | you may not use this file except in compliance with the License.
195 | You may obtain a copy of the License at
196 |
197 | http://www.apache.org/licenses/LICENSE-2.0
198 |
199 | Unless required by applicable law or agreed to in writing, software
200 | distributed under the License is distributed on an "AS IS" BASIS,
201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
202 | See the License for the specific language governing permissions and
203 | limitations under the License.
204 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | Android BatchStepSensor Sample
3 | ==============================
4 |
5 | This repo has been migrated to [github.com/android/sensors][1]. Please check that repo for future updates. Thank you!
6 |
7 | [1]: https://github.com/android/sensors
8 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/packaging.yaml:
--------------------------------------------------------------------------------
1 | # GOOGLE SAMPLE PACKAGING DATA
2 | #
3 | # This file is used by Google as part of our samples packaging process.
4 | # End users may safely ignore this file. It has no relevance to other systems.
5 | ---
6 |
7 | status: PUBLISHED
8 | technologies: [Android]
9 | categories: [Sensors]
10 | languages: [Java]
11 | solutions: [Mobile]
12 | github: googlesamples/android-BatchStepSensor
13 | level: BEGINNER
14 | icon: BatchStepSensorSample/screenshots/big_icon.png
15 | license: apache2-android
16 |
--------------------------------------------------------------------------------
/screenshots/big_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/screenshots/big_icon.png
--------------------------------------------------------------------------------
/screenshots/screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/screenshots/screenshot1.png
--------------------------------------------------------------------------------
/screenshots/screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/screenshots/screenshot2.png
--------------------------------------------------------------------------------
/screenshots/screenshot3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/screenshots/screenshot3.png
--------------------------------------------------------------------------------
/screenshots/screenshot4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/screenshots/screenshot4.png
--------------------------------------------------------------------------------
/screenshots/screenshot5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/googlearchive/android-BatchStepSensor/28c93504fd62abac04c0fb8cc152c423713f85f6/screenshots/screenshot5.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include 'Application'
2 |
--------------------------------------------------------------------------------