Java tutorial
/* * Copyright (C) 2009, DroidSensor - http://code.google.com/p/droidsensor/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sevenleaves.droidsensor; import static org.sevenleaves.droidsensor.ServiceUtils.callLater; import static org.sevenleaves.droidsensor.ServiceUtils.cancelImmediatly; import static org.sevenleaves.droidsensor.ServiceUtils.isActionContinue; import static org.sevenleaves.droidsensor.ServiceUtils.isStopAction; import java.util.Calendar; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.sevenleaves.droidsensor.DatabaseManipulation.ManipulationScope; import org.sevenleaves.droidsensor.bluetooth.BluetoothDeviceStub; import org.sevenleaves.droidsensor.bluetooth.BluetoothDeviceStubFactory; import org.sevenleaves.droidsensor.bluetooth.BluetoothSettings; import org.sevenleaves.droidsensor.bluetooth.BluetoothUtils; import org.sevenleaves.droidsensor.handlers.BluetoothEventControllerImpl; import org.sevenleaves.droidsensor.handlers.BluetoothState; import org.sevenleaves.droidsensor.handlers.BluetoothStateListenerAdapter; import org.sevenleaves.droidsensor.handlers.DiscoveryCompletedHandler; import org.sevenleaves.droidsensor.handlers.DiscoveryStartedHandler; import org.sevenleaves.droidsensor.handlers.ScanModeConnectableDiscoverableHandler; import org.sevenleaves.droidsensor.handlers.ScanModeConnectableHandler; import org.sevenleaves.droidsensor.handlers.ScanModeNoneHandler; import org.sevenleaves.droidsensor.handlers.StateOffHandler; import org.sevenleaves.droidsensor.handlers.StateOnHandler; import org.sevenleaves.droidsensor.handlers.StateTurningOffHandler; import org.sevenleaves.droidsensor.handlers.StateTurningOnHandler; import twitter4j.TwitterException; import android.content.Intent; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.Handler.Callback; import android.util.Log; /** * @author esmasui@gmail.com * */ public class DroidSensorService extends ServiceSupport { /** * ?BluetoothOFF/ON?????. * Donut?Discovery????????. * ????????????????. */ private class DonutRemoteDeviceHandler extends RemoteDeviceHandler { @Override public void onScanModeChangedConnectable() { getBluetoothDevice().stopPeriodicDiscovery(); getBluetoothDevice().disable(); } } /** * ?BluetoothOFF/ON?????. * Donut?Discovery????????. */ private class DonutScanModeNoneHandler extends ScanModeNoneHandler { @Override public void onStateChangedOff() { getBluetoothDevice().enable(); } } /** * ?Bluetooth?OFF???? * ON?????bluetooth???????????. * */ private class RegisterAddressHandler extends StateTurningOnHandler { boolean _registerd; @Override public void onStateChangedOn() { if (!_registerd) { // TODO ??????. boolean succeed = registerAddress(); } _registerd = true; super.onStateChangedOn(); } } /** * Bluetooth?????????????. * ???ConnectableDiscoverable???????????????????. * */ private class RemoteDeviceHandler extends ScanModeConnectableDiscoverableHandler { @Override public void onRemoteDeviceDisappeared(String address) { _devices.remove(address); } @Override public void onRemoteDeviceFound(String address) { if (_devices.contains(address)) { return; } BluetoothDeviceStub stub = BluetoothDeviceStubFactory .createBluetoothServiceStub(DroidSensorService.this); String name = stub.getRemoteName(address); if (name == null) { return; } DroidSensorService.this.onRemoteDeviceFound(address, name); } @Override public void onRemoteNameUpdated(String address, String name) { DroidSensorService.this.onRemoteDeviceFound(address, name); } } private static final int REMOTE_DEVICE_FOUND_MESSAGE = 1; /** * Log?. */ private static final String TAG = DroidSensorService.class.getSimpleName(); private static final long INTERVAL_SECONDS = 10L; private BluetoothStateListenerAdapter _receiver; private BluetoothEventControllerImpl _controller; private volatile boolean _started; private DroidSensorInquiry _droidSensorInquiry; /** * ?????????Bluetooth???. */ private Set<String> _devices; private final RemoteCallbackList<IDroidSensorCallbackListener> _listeners = new RemoteCallbackList<IDroidSensorCallbackListener>(); private Handler _handler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what != REMOTE_DEVICE_FOUND_MESSAGE) { super.dispatchMessage(msg); return; } for (int i = 0, size = _listeners.beginBroadcast(); i < size; ++i) { IDroidSensorCallbackListener item = _listeners.getBroadcastItem(i); try { item.deviceFound((String) msg.obj); } catch (RemoteException e) { Log.e(TAG, e.getLocalizedMessage(), e); } } _listeners.finishBroadcast(); }; }; private final IDroidSensorService.Stub _binder = new IDroidSensorService.Stub() { public void addListener(IDroidSensorCallbackListener listener) throws RemoteException { _listeners.register(listener); } public boolean isStarted() throws RemoteException { return _receiver != null; } public void removeListener(IDroidSensorCallbackListener listener) throws RemoteException { _listeners.unregister(listener); } public void stopService() throws RemoteException { DroidSensorService.this.stopService(); } }; public DroidSensorService() { _devices = Collections.synchronizedSet(new HashSet<String>()); } @Override public IBinder onBind(Intent intent) { return _binder; } @Override public void onCreate() { Log.d(TAG, "service create"); super.onCreate(); } @Override public void onDestroy() { Log.d(TAG, "service destroy"); super.onDestroy(); try { _receiver.unregisterSelf(this); } catch (Exception e) { // nop. } if (_droidSensorInquiry != null) { _droidSensorInquiry.cancelAll(); _droidSensorInquiry = null; } _receiver = null; _controller = null; _started = false; _devices.clear(); BluetoothSettings.load(this); hideNotification(); } @Override public void onStart(Intent intent, int startId) { super.onStart(intent, startId); if (isStopAction(intent)) { if (_started) { stopService(); } return; } if (isActionContinue(intent)) { _started = true; Log.d(TAG, "running"); if (_started) { if (_droidSensorInquiry == null) { _droidSensorInquiry = new DroidSensorInquiry(DroidSensorService.this); } if (_receiver == null) { BluetoothSettings.save(this); showNotification(); _controller = createController(); _receiver = createReceiver(_controller); _receiver.registerSelf(this); fireEvent(); } // callLater(DroidSensorService.this, IDroidSensorService.class, // INTERVAL_SECONDS); callLater(DroidSensorService.this, DroidSensorService.class, INTERVAL_SECONDS); } } } public void stopService() { Log.d(TAG, "stopService"); cancelImmediatly(this, DroidSensorService.class); stopSelf(); try { _receiver.unregisterSelf(this); } catch (Exception e) { // nop. } if (_droidSensorInquiry != null) { _droidSensorInquiry.cancelAll(); _droidSensorInquiry = null; } _receiver = null; _controller = null; hideNotification(); _started = false; _devices.clear(); BluetoothSettings.load(this); } /** * ??????. * * @return */ private BluetoothEventControllerImpl createController() { BluetoothEventControllerImpl res = new BluetoothEventControllerImpl(this); // res.addHandler(new ScanModeConnectableDiscoverableHandler()); RemoteDeviceHandler remoteDeviceHandler = createRemoteDeviceHandler(); res.addHandler(remoteDeviceHandler); res.addHandler(new ScanModeConnectableHandler()); // res.addHandler(new ScanModeNoneHandler()); ScanModeNoneHandler scanModeNoneHandler = createScanModeNoneHandler(); res.addHandler(scanModeNoneHandler); res.addHandler(new StateOffHandler()); // res.addHandler(new StateTurningOnHandler()); res.addHandler(new RegisterAddressHandler()); res.addHandler(new StateOnHandler()); res.addHandler(new StateTurningOffHandler()); res.addHandler(new DiscoveryStartedHandler()); res.addHandler(new DiscoveryCompletedHandler()); return res; } private BluetoothStateListenerAdapter createReceiver(BluetoothEventControllerImpl controller) { BluetoothStateListenerAdapter res = new BluetoothStateListenerAdapter(); res.setHandler(controller); return res; } /** * {@link RemoteDeviceHandler}?. * toggleBluetoothOnOff????Donut?????. * * @return */ private RemoteDeviceHandler createRemoteDeviceHandler() { SettingsManager settings = SettingsManager.getInstance(DroidSensorService.this); if (settings.isToggleBluetooth()) { return new DonutRemoteDeviceHandler(); } return new RemoteDeviceHandler(); } /** * * {@link ScanModeNoneHandler}?. * toggleBluetoothOnOff????Donut?????. * * @return */ private ScanModeNoneHandler createScanModeNoneHandler() { SettingsManager settings = SettingsManager.getInstance(DroidSensorService.this); if (settings.isToggleBluetooth()) { return new DonutScanModeNoneHandler(); } return new ScanModeNoneHandler(); } /** * ?????. */ private void fireEvent() { BluetoothDeviceStub bt = _controller.getBluetoothDevice(); if (bt.isEnabled()) { boolean succeed = registerAddress(); if (bt.isDiscovering()) { _controller.setCurrentState(BluetoothState.DISCOVERY_STARTED); bt.cancelDiscovery(); return; } _controller.setCurrentState(BluetoothState.BLUETOOTH_STATE_ON); bt.setScanMode(0x3); return; } _controller.setCurrentState(BluetoothState.BLUETOOTH_STATE_OFF); bt.enable(); } /** * ????????????. * * @param settings * @param id * @return ???true????false?. */ private boolean isDeviceWillTweet(SettingsManager settings, String id) { String myId = settings.getTwitterId(); if (isUser(id, myId)) { return true; } if (!settings.isAllBluetoothDevices()) { return false; } if (isPassedByUser(id, myId)) { return settings.isDetailPassedUser(); } if (isPassedByMe(id, myId)) { return settings.isDetailPassedMe(); } return settings.isDetailPassedNo(); } /** * ?????????????. * * @param bluetooth * @return ????????true????????false?. */ private boolean isDiscoverable(BluetoothDeviceStub bluetooth) { boolean res = (bluetooth.getScanMode() == BluetoothDeviceStub.SCAN_MODE_CONNECTABLE_DISCOVERABLE); return res; } /** * ???????. * * @param str * @return ???true???????false?. */ private boolean isEmpty(String str) { if (str == null) { return true; } if (str.trim().length() == 0) { return true; } return false; } /** * ?????????????????. * * @param id * @param myId * @return */ private boolean isPassedByMe(String id, String myId) { return "@".concat(myId).equals(id); } /** * ??????????????????. * * @param id * @param myId * @return */ private boolean isPassedByUser(String id, String myId) { String s = safeString(id); if (!s.startsWith("@")) { return false; } return !isPassedByMe(id, myId); } /** * ??????????????????. * * @param id * @param myId * @return */ private boolean isUser(String id, String myId) { if (isEmpty(id)) { return false; } if (isPassedByMe(id, myId)) { return false; } if (isPassedByUser(id, myId)) { return false; } return true; } /** * ???? * * @param address * @param name */ private void onRemoteDeviceFound(final String address, String name) { if (_devices.contains(address)) { return; } // device-found, name-update??????? // ????twitterID??????????????????? if (name == null) { return; } BluetoothDeviceStub bluetooth = BluetoothDeviceStubFactory .createBluetoothServiceStub(DroidSensorService.this); // ???????????????????? if (!isDiscoverable(bluetooth)) { return; } SettingsManager settings = SettingsManager.getInstance(DroidSensorService.this); final String fixedName; if (name.trim().length() > 0) { fixedName = name; } else { fixedName = "*unknown*"; } _droidSensorInquiry.getTwitterUser(address, settings.getTwitterId(), settings.getDefaultMessage(), new Callback() { public boolean handleMessage(Message msg) { Bundle data = msg.getData(); String id = data.getString(DroidSensorInquiry.TWITTER_USER); String message = data.getString(DroidSensorInquiry.MESSAGE); Log.d(TAG, "id:" + id); tweetDeviceFound(address, fixedName, id, message); return true; } }); } private void persistBluetoothDevice(final String address, final String name, final String twitterID, final String message, final boolean tweeted) { DatabaseManipulation.manipulate(this, new ManipulationScope() { public void execute(SQLiteDatabase db) { BluetoothDeviceStub stub = BluetoothDeviceStubFactory .createBluetoothServiceStub(DroidSensorService.this); BluetoothDeviceEntityDAO dao = new BluetoothDeviceEntityDAO(db); BluetoothDeviceEntity e; // ??????. // ohgro:???????????????????????????????????????????????#droidsensor e = new BluetoothDeviceEntity(); e.setAddress(address); // e.setRSSI(); e.setName(name); e.setDeviceClass(stub.getRemoteClass(address)); e.setCompany(stub.getRemoteCompany(address)); e.setManufacturer(stub.getRemoteManufacturer(address)); e.setTwitterID(twitterID); e.setMessage(message); // e.setLongitude(); // e.setLatitude(); e.setCount(1); // e.setStatus(); e.setStatus(tweeted ? 1 : 0); e.setUpdated(Calendar.getInstance().getTimeInMillis()); dao.insert(e); } }); } /** * DroidSensor??Bluetooth?????. * * @return */ private boolean registerAddress() { BluetoothDeviceStub stub = BluetoothDeviceStubFactory.createBluetoothServiceStub(this); SettingsManager settings = SettingsManager.getInstance(this); String address = stub.getAddress(); try { // second-account????(address????) Log.d(TAG, "register twitter ID"); boolean succeed = DroidSensorUtils.putTwitterId(settings.getApiUrl(), address, settings.getTwitterId(), settings.getDefaultMessage()); return succeed; } catch (Exception e) { return false; } } private String safeString(String str) { if (isEmpty(str)) { return ""; } return str.trim(); } private void sendMessage(String address) { Message msg = new Message(); msg.obj = address; msg.what = REMOTE_DEVICE_FOUND_MESSAGE; _handler.sendMessage(msg); } private String convertSpecialDevice(String name, String device) { if (name == null) { return device; } String lower = name.toLowerCase(); if (lower.contains("iphone")) { return "iPhone"; } if (lower.contains("ipod")) { return "iPod"; } return device; } private void tweetDeviceFound(String address, String name, String id, String message) { SettingsManager settings = SettingsManager.getInstance(DroidSensorService.this); if (!isDeviceWillTweet(settings, id)) { persistBluetoothDevice(address, name, id, message, false); sendMessage(address); _devices.add(address); return; } String tweeted; BluetoothDeviceStub bluetooth = BluetoothDeviceStubFactory.createBluetoothServiceStub(this); int btClass = bluetooth.getRemoteClass(address); try { tweeted = TwitterUtils.tweetDeviceFound(address, name, id, message, convertSpecialDevice(name, BluetoothUtils.getMajorDeviceClassName(this, btClass)), settings); } catch (TwitterException e) { if (e.getStatusCode() == 401) { String error = "Could not authenticate you."; String pref = "Error from Twitter:"; showDeviceFound(pref + error); } Log.e(TAG, e.getLocalizedMessage(), e); return; } if (tweeted == null) { return; } Log.d(TAG, address + "(" + name + ")" + " found."); persistBluetoothDevice(address, name, id, message, true); _devices.add(address); sendMessage(address); showDeviceFound(tweeted); } }