1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.nfc;
18
19import android.app.NotificationManager;
20import android.content.Context;
21import android.content.res.Configuration;
22import android.os.Vibrator;
23
24/**
25 * Manages vibration, sound and animation for P2P events.
26 */
27public class P2pEventManager implements P2pEventListener, SendUi.Callback {
28    static final String TAG = "NfcP2pEventManager";
29    static final boolean DBG = true;
30
31    static final long[] VIBRATION_PATTERN = {0, 100, 10000};
32
33    final Context mContext;
34    final NfcService mNfcService;
35    final P2pEventListener.Callback mCallback;
36    final Vibrator mVibrator;
37    final NotificationManager mNotificationManager;
38    final SendUi mSendUi;
39
40    // only used on UI thread
41    boolean mSending;
42    boolean mNdefSent;
43    boolean mNdefReceived;
44    boolean mInDebounce;
45
46    public P2pEventManager(Context context, P2pEventListener.Callback callback) {
47        mNfcService = NfcService.getInstance();
48        mContext = context;
49        mCallback = callback;
50        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
51        mNotificationManager = (NotificationManager) mContext.getSystemService(
52                Context.NOTIFICATION_SERVICE);
53
54        mSending = false;
55        final int uiModeType = mContext.getResources().getConfiguration().uiMode
56                & Configuration.UI_MODE_TYPE_MASK;
57        if (uiModeType == Configuration.UI_MODE_TYPE_APPLIANCE) {
58            // "Appliances" don't intrinsically have a way of confirming this, so we
59            // don't use the UI and just autoconfirm where necessary.
60            // Don't instantiate SendUi or else we'll use memory and never reclaim it.
61            mSendUi = null;
62        } else {
63            mSendUi = new SendUi(context, this);
64        }
65    }
66
67    @Override
68    public void onP2pInRange() {
69        mNfcService.playSound(NfcService.SOUND_START);
70        mNdefSent = false;
71        mNdefReceived = false;
72        mInDebounce = false;
73
74        mVibrator.vibrate(VIBRATION_PATTERN, -1);
75        if (mSendUi != null) {
76            mSendUi.takeScreenshot();
77        }
78    }
79
80    @Override
81    public void onP2pNfcTapRequested() {
82        mNfcService.playSound(NfcService.SOUND_START);
83        mNdefSent = false;
84        mNdefReceived = false;
85        mInDebounce = false;
86
87        mVibrator.vibrate(VIBRATION_PATTERN, -1);
88        if (mSendUi != null) {
89            mSendUi.takeScreenshot();
90            mSendUi.showPreSend(true);
91        }
92    }
93
94    @Override
95    public void onP2pTimeoutWaitingForLink() {
96        if (mSendUi != null) {
97            mSendUi.finish(SendUi.FINISH_SCALE_UP);
98        }
99    }
100
101    @Override
102    public void onP2pSendConfirmationRequested() {
103        if (mSendUi != null) {
104            mSendUi.showPreSend(false);
105        } else {
106            mCallback.onP2pSendConfirmed();
107        }
108    }
109
110    @Override
111    public void onP2pSendComplete() {
112        mNfcService.playSound(NfcService.SOUND_END);
113        mVibrator.vibrate(VIBRATION_PATTERN, -1);
114        if (mSendUi != null) {
115            mSendUi.finish(SendUi.FINISH_SEND_SUCCESS);
116        }
117        mSending = false;
118        mNdefSent = true;
119    }
120
121    @Override
122    public void onP2pHandoverNotSupported() {
123        mNfcService.playSound(NfcService.SOUND_ERROR);
124        mVibrator.vibrate(VIBRATION_PATTERN, -1);
125        mSendUi.finishAndToast(SendUi.FINISH_SCALE_UP,
126                mContext.getString(R.string.beam_handover_not_supported));
127        mSending = false;
128        mNdefSent = false;
129    }
130
131    @Override
132    public void onP2pReceiveComplete(boolean playSound) {
133        mVibrator.vibrate(VIBRATION_PATTERN, -1);
134        if (playSound) mNfcService.playSound(NfcService.SOUND_END);
135        if (mSendUi != null) {
136            // TODO we still don't have a nice receive solution
137            // The sanest solution right now is just to scale back up what we had
138            // and start the new activity. It is not perfect, but at least it is
139            // consistent behavior. All other variants involve making the old
140            // activity screenshot disappear, and then removing the animation
141            // window hoping the new activity has started by then. This just goes
142            // wrong too often and can look weird.
143            mSendUi.finish(SendUi.FINISH_SCALE_UP);
144        }
145        mNdefReceived = true;
146    }
147
148    @Override
149    public void onP2pOutOfRange() {
150        if (mSending) {
151            mNfcService.playSound(NfcService.SOUND_ERROR);
152            mSending = false;
153        }
154        if (!mNdefSent && !mNdefReceived && mSendUi != null) {
155            mSendUi.finish(SendUi.FINISH_SCALE_UP);
156        }
157        mInDebounce = false;
158    }
159
160    @Override
161    public void onSendConfirmed() {
162        if (!mSending) {
163            if (mSendUi != null) {
164                mSendUi.showStartSend();
165            }
166            mCallback.onP2pSendConfirmed();
167        }
168        mSending = true;
169
170    }
171
172    @Override
173    public void onCanceled() {
174        mSendUi.finish(SendUi.FINISH_SCALE_UP);
175        mCallback.onP2pCanceled();
176    }
177
178    @Override
179    public void onP2pSendDebounce() {
180        mInDebounce = true;
181        mNfcService.playSound(NfcService.SOUND_ERROR);
182        if (mSendUi != null) {
183            mSendUi.showSendHint();
184        }
185    }
186
187    @Override
188    public void onP2pResumeSend() {
189        if (mInDebounce) {
190            mVibrator.vibrate(VIBRATION_PATTERN, -1);
191            mNfcService.playSound(NfcService.SOUND_START);
192            if (mSendUi != null) {
193                mSendUi.showStartSend();
194            }
195        }
196        mInDebounce = false;
197    }
198
199}
200