P2pEventManager.java revision 3a596230af0e497ef5980441818fb1a20bacc74c
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.Notification; 20import android.app.NotificationManager; 21import android.app.PendingIntent; 22import android.content.Context; 23import android.content.Intent; 24import android.content.SharedPreferences; 25import android.media.AudioManager; 26import android.media.SoundPool; 27import android.os.Vibrator; 28import android.provider.Settings; 29import android.view.OrientationEventListener; 30 31import com.android.nfc3.R; 32 33/** 34 * Manages vibration, sound and animation for P2P events. 35 */ 36public class P2pEventManager implements P2pEventListener { 37 static final String TAG = "NfcP2pEventManager"; 38 static final boolean DBG = true; 39 40 static final String PREF_FIRST_SHARE = "first_share"; 41 static final int NOTIFICATION_FIRST_SHARE = 0; 42 43 static final long[] VIBRATION_PATTERN = {0, 100, 10000}; 44 45 final Context mContext; 46 final P2pEventListener.Callback mCallback; 47 final SharedPreferences mPrefs; 48 final int mStartSound; 49 final int mEndSound; 50 final int mErrorSound; 51 final SoundPool mSoundPool; // playback synchronized on this 52 final Vibrator mVibrator; 53 final RotationDetector mRotationDetector; 54 final NotificationManager mNotificationManager; 55 56 boolean mAnimating; 57 boolean mPrefsFirstShare; 58 59 class RotationDetector extends OrientationEventListener { 60 static final int THRESHOLD_DEGREES = 35; 61 int mStartOrientation; 62 boolean mRotateDetectionEnabled; 63 64 public RotationDetector(Context context) { 65 super(context); 66 } 67 public void start() { 68 synchronized (RotationDetector.this) { 69 mRotateDetectionEnabled = true; 70 mStartOrientation = -1; 71 super.enable(); 72 } 73 } 74 public void cancel() { 75 synchronized (RotationDetector.this) { 76 mRotateDetectionEnabled = false; 77 super.disable(); 78 } 79 } 80 @Override 81 public void onOrientationChanged(int orientation) { 82 synchronized (RotationDetector.this) { 83 if (!mRotateDetectionEnabled) { 84 return; 85 } 86 if (mStartOrientation < 0) { 87 mStartOrientation = orientation; 88 } 89 int diff = Math.abs(mStartOrientation - orientation); 90 if (diff > THRESHOLD_DEGREES && diff < (360-THRESHOLD_DEGREES)) { 91 cancel(); 92 mVibrator.vibrate(VIBRATION_PATTERN, -1); 93 mCallback.onP2pSendConfirmed(); 94 } 95 } 96 } 97 } 98 99 public P2pEventManager(Context context, P2pEventListener.Callback callback) { 100 mContext = context; 101 mCallback = callback; 102 mRotationDetector = new RotationDetector(mContext); 103 mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0); 104 mStartSound = mSoundPool.load(mContext, R.raw.start, 1); 105 mEndSound = mSoundPool.load(mContext, R.raw.end, 1); 106 mErrorSound = mSoundPool.load(mContext, R.raw.error, 1); 107 mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); 108 mNotificationManager = (NotificationManager) mContext.getSystemService( 109 Context.NOTIFICATION_SERVICE); 110 111 SharedPreferences prefs = mContext.getSharedPreferences(NfcService.PREF, 112 Context.MODE_PRIVATE); 113 if (prefs.getBoolean(PREF_FIRST_SHARE, true)) { 114 mPrefs = prefs; 115 mPrefsFirstShare = true; 116 } else { 117 // don't need to check pref again 118 mPrefs = null; 119 mPrefsFirstShare = false; 120 } 121 122 mAnimating = false; 123 } 124 125 @Override 126 public void onP2pInRange() { 127 mVibrator.vibrate(VIBRATION_PATTERN, -1); 128 playSound(mStartSound); 129 } 130 131 @Override 132 public void onP2pSendConfirmationRequested() { 133 mRotationDetector.start(); 134 P2pAnimationActivity.makeScreenshot(mContext); 135 P2pAnimationActivity.setCallback(mCallback); 136 mAnimating = true; 137 // Start the animation activity 138 Intent animIntent = new Intent(); 139 animIntent.setClass(mContext, P2pAnimationActivity.class); 140 animIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NEW_TASK); 141 mContext.startActivity(animIntent); 142 } 143 144 @Override 145 public void onP2pSendComplete(boolean result) { 146 if (!result) { 147 playSound(mErrorSound); 148 } else { 149 playSound(mEndSound); 150 checkFirstShare(); 151 } 152 finish(result, false); 153 } 154 155 @Override 156 public void onP2pReceiveComplete() { 157 mRotationDetector.cancel(); 158 finish(false, true); 159 } 160 161 @Override 162 public void onP2pOutOfRange() { 163 mRotationDetector.cancel(); 164 if (mAnimating) { 165 finish(false, false); 166 playSound(mErrorSound); 167 } 168 } 169 170 /** 171 * Finish up the animation, if running, and play ending sounds. 172 * Must be called on the UI thread. 173 */ 174 void finish(boolean sendSuccess, boolean receiveSuccess) { 175 if (sendSuccess) { 176 if (mAnimating) { 177 P2pAnimationActivity.finishWithSend(); 178 } 179 } else if (receiveSuccess) { 180 if (mAnimating) { 181 P2pAnimationActivity.finishWithReceive(); 182 } 183 } else { 184 if (mAnimating) { 185 P2pAnimationActivity.finishWithFailure(); 186 } 187 } 188 mAnimating = false; 189 } 190 191 /** If first time, display up a notification */ 192 void checkFirstShare() { 193 synchronized (this) { 194 if (mPrefsFirstShare) { 195 mPrefsFirstShare = false; 196 SharedPreferences.Editor editor = mPrefs.edit(); 197 editor.putBoolean(PREF_FIRST_SHARE, false); 198 editor.apply(); 199 200 Intent intent = new Intent(Settings.ACTION_NFCSHARING_SETTINGS); 201 PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 202 PendingIntent.FLAG_UPDATE_CURRENT); 203 Notification notification = new Notification.Builder(mContext) 204 .setContentTitle(mContext.getString(R.string.first_share_title)) 205 .setContentText(mContext.getString(R.string.first_share_text)) 206 .setContentIntent(pi) 207 .setSmallIcon(R.drawable.stat_sys_nfc) 208 .setAutoCancel(true) 209 .getNotification(); 210 mNotificationManager.notify(NOTIFICATION_FIRST_SHARE, notification); 211 } 212 } 213 } 214 215 void playSound(int sound) { 216 synchronized (this) { 217 mSoundPool.play(sound, 1.0f, 1.0f, 0, 0, 1.0f); 218 } 219 } 220} 221