Android Open Source - p1keyboard Bluez Service






From Project

Back to project page p1keyboard.

License

The source code is released under:

GNU Lesser General Public License

If you think the Android project p1keyboard listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/* Copyright (C) 2011, Kenneth Skovhede
 * http://www.hexad.dk, opensource@hexad.dk
 * //from  w w w . j  av  a 2  s. c  o  m
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
package mobi.omegacentauri.p1keyboard;

import java.util.ArrayList;
import java.util.Hashtable;

import mobi.omegacentauri.p1keyboard.R;

import android.app.IntentService;
import android.bluetooth.BluetoothAdapter;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class BluezService extends IntentService {
  
  
  private static final String[] BASE_DRIVER_NAMES = {
    PalmOneWirelessKeyboardReader.DRIVER_NAME,
    ZeemoteReader.DRIVER_NAME, 
    BGP100Reader.DRIVER_NAME, 
    PhonejoyReader.DRIVER_NAME,
    iControlPadReader.DRIVER_NAME,
    GameStopReader.DRIVER_NAME,
    DataDumpReader.DRIVER_NAME,
  };
  
  private static final String[] BASE_DRIVER_DISPLAYNAMES = {
    PalmOneWirelessKeyboardReader.DISPLAY_NAME,
    ZeemoteReader.DISPLAY_NAME, 
    BGP100Reader.DISPLAY_NAME, 
    PhonejoyReader.DISPLAY_NAME,
    iControlPadReader.DISPLAY_NAME,
    GameStopReader.DISPLAY_NAME,
    DataDumpReader.DISPLAY_NAME,
  };
  
  private static final String[] HID_DRIVER_NAMES = {
    WiimoteReader.DRIVER_NAME,
    HIDKeyboard.DRIVER_NAME,
    iCadeReader.DRIVER_NAME,
        HIDipega.DRIVER_NAME
  };

  private static final String[] HID_DRIVER_DISPLAYNAMES = {
    WiimoteReader.DISPLAY_NAME,
    HIDKeyboard.DRIVER_DISPLAYNAME,
    iCadeReader.DRIVER_DISPLAYNAME,
        HIDipega.DRIVER_DISPLAYNAME
  };

  public static final String SESSION_ID = "mobi.omegacentauri.p1keyboard.sessionid";
  public static final String DEFAULT_SESSION_NAME = "mobi.omegacentauri.p1keyboard.default_session";
  
  public static final String EVENT_KEYPRESS = "mobi.omegacentauri.p1keyboard.keypress";
  public static final String EVENT_KEYPRESS_KEY = "key";
  public static final String EVENT_KEYPRESS_ACTION = "action";
  public static final String EVENT_KEYPRESS_MODIFIERS = "modifiers";
  public static final String EVENT_KEYPRESS_ANALOG_EMULATED = "emulated";
  public static final String EVENT_KEYPRESS_SPECIAL = "special_key";

  public static final String EVENT_DIRECTIONALCHANGE = "mobi.omegacentauri.p1keyboard.directionalchange";
  public static final String EVENT_DIRECTIONALCHANGE_DIRECTION = "direction";
  public static final String EVENT_DIRECTIONALCHANGE_VALUE = "value";

  public static final String EVENT_ACCELEROMETERCHANGE = "mobi.omegacentauri.p1keyboard.accelerometerchange";
  public static final String EVENT_ACCELEROMETERCHANGE_AXIS = "axis";
  public static final String EVENT_ACCELEROMETERCHANGE_VALUE = "value";

  public static final String EVENT_CONNECTING = "mobi.omegacentauri.p1keyboard.connecting";
  public static final String EVENT_CONNECTING_ADDRESS = "address";

  public static final String EVENT_CONNECTED = "mobi.omegacentauri.p1keyboard.connected";
  public static final String EVENT_CONNECTED_ADDRESS = "address";

  public static final String EVENT_DISCONNECTED = "mobi.omegacentauri.p1keyboard.disconnected";
  public static final String EVENT_DISCONNECTED_ADDRESS = "address";

  public static final String EVENT_ERROR = "mobi.omegacentauri.p1keyboard.error";
  public static final String EVENT_ERROR_SHORT = "message";
  public static final String EVENT_ERROR_FULL = "stacktrace";

  public static final String REQUEST_CONNECT = "mobi.omegacentauri.p1keyboard.connect";
  public static final String REQUEST_CONNECT_ADDRESS = "address";
  public static final String REQUEST_CONNECT_DRIVER = "driver";
  public static final String REQUEST_CONNECT_USE_UI = "use-ui-setup";
  public static final String REQUEST_CONNECT_CREATE_NOTIFICATION = "registernotification";
    
  public static final String REQUEST_DISCONNECT = "mobi.omegacentauri.p1keyboard.disconnect";
  
  public static final String REQUEST_STATE = "mobi.omegacentauri.p1keyboard.getstate";
  
  public static final String EVENT_REPORTSTATE = "mobi.omegacentauri.p1keyboard.currentstate";
  public static final String EVENT_REPORTSTATE_CONNECTED = "connected";
  public static final String EVENT_REPORTSTATE_DEVICENAME = "devicename";
  public static final String EVENT_REPORTSTATE_DISPLAYNAME = "displayname";
  public static final String EVENT_REPORTSTATE_DRIVERNAME = "drivername";
  
  //The service caller can also activate these, but they are not used by Bluez-IME (=> Not tested!)
  public static final String REQUEST_FEATURECHANGE = "mobi.omegacentauri.p1keyboard.featurechange";
  public static final String REQUEST_FEATURECHANGE_RUMBLE = "rumble"; //Boolean, true=on, false=off
  public static final String REQUEST_FEATURECHANGE_LEDID = "ledid"; //Integer, LED to use 1-4 for Wiimote
  public static final String REQUEST_FEATURECHANGE_ACCELEROMETER = "accelerometer"; //Boolean, true=on, false=off

  public static final String REQUEST_CONFIG = "mobi.omegacentauri.p1keyboard.getconfig";
  
  public static final String EVENT_REPORT_CONFIG = "mobi.omegacentauri.p1keyboard.config";
  public static final String EVENT_REPORT_CONFIG_VERSION = "version";
  public static final String EVENT_REPORT_CONFIG_DRIVER_NAMES = "drivernames";
  public static final String EVENT_REPORT_CONFIG_DRIVER_DISPLAYNAMES = "driverdisplaynames";
  
  private static final String LOG_NAME = "BluezIME:BluezService";
  
  public static final int SPECIAL_COPY = 1;
  public static final int SPECIAL_CUT = 2;
  public static final int SPECIAL_PASTE = 3;
  public static final int SPECIAL_SELECT_ALL = 4;

  public static final int SPECIAL_HOME = 5;

  public static final int SPECIAL_UNICODE = 6;

  private final Binder binder = new LocalBinder();
  
  //private static BluezDriverInterface m_reader = null;
  private static Hashtable<String, BluezDriverInterface> m_readers = new Hashtable<String, BluezDriverInterface>();

  private static boolean hasProbedForHID = false;
  private static boolean supportsHID = false;
  
  public BluezService() {
    super(LOG_NAME);
  }

  @Override
  public void onCreate() {
    super.onCreate();
  }
  
  public class LocalBinder extends Binder {
    BluezService getService() {
      return(BluezService.this);
    }
  }

  @Override
  public IBinder onBind(Intent intent) {
    return binder;
  }

  @Override
  protected void onHandleIntent(Intent intent) {
    if (intent == null || intent.getAction() == null)
      return;
    
    String sessionId = DEFAULT_SESSION_NAME;
    if (intent.hasExtra(SESSION_ID))
      sessionId = intent.getStringExtra(SESSION_ID);
    
    BluezDriverInterface reader = null;
    synchronized (m_readers) {
      if (sessionId != null && m_readers.containsKey(sessionId))
        reader = m_readers.get(sessionId);
    }

    if (intent.getAction().equals(REQUEST_CONNECT)) {
      Log.d(LOG_NAME, "Request connect");
            String address = null;
            String driver = null;
      
      if (intent.hasExtra(REQUEST_CONNECT_ADDRESS))
        address = intent.getStringExtra(REQUEST_CONNECT_ADDRESS);
      if (intent.hasExtra(REQUEST_CONNECT_DRIVER))
        driver = intent.getStringExtra(REQUEST_CONNECT_DRIVER);
      
      if (address == null || driver == null) {
        boolean use_ui = intent.getBooleanExtra(REQUEST_CONNECT_USE_UI, false);
        Preferences p = new Preferences(this);

        if (address == null)
          address = p.getSelectedDeviceAddress(0);
        if (driver == null)
          driver = p.getSelectedDriverName(0);
              
              if (!use_ui) {
                Log.w(LOG_NAME, "No driver/address set for connect request, please update your application. If this is intentional, please set the option " + REQUEST_CONNECT_USE_UI + " to true");
              }
      }
      
      boolean startnotification = intent.getBooleanExtra(REQUEST_CONNECT_CREATE_NOTIFICATION, true);
      connectToDevice(address, driver, sessionId, startnotification);
    } else if (intent.getAction().equals(REQUEST_DISCONNECT)) {
      Log.v(LOG_NAME, "Request disconnect");
      disconnectFromDevice(sessionId);
    } else if (intent.getAction().equals(REQUEST_FEATURECHANGE)) {
      try 
      {
        //NOTE: Not tested!
        
        if (intent.hasExtra(REQUEST_FEATURECHANGE_RUMBLE)) {
          if (reader != null && reader instanceof WiimoteReader) {
            ((WiimoteReader)reader).request_SetRumble(intent.getBooleanExtra(REQUEST_FEATURECHANGE_RUMBLE, false));
          }
        }

        if (intent.hasExtra(REQUEST_FEATURECHANGE_ACCELEROMETER)) {
          if (reader != null && reader instanceof WiimoteReader) {
            ((WiimoteReader)reader).request_UseAccelerometer(intent.getBooleanExtra(REQUEST_FEATURECHANGE_ACCELEROMETER, false));
          }
        }

        if (intent.hasExtra(REQUEST_FEATURECHANGE_LEDID)) {
          if (reader != null && reader instanceof WiimoteReader) {
            int led = intent.getIntExtra(REQUEST_FEATURECHANGE_LEDID, 1);
            ((WiimoteReader)reader).request_SetLEDState(led == 1, led == 2, led == 3, led ==4);
          }
        }
      } catch (Exception ex) {
        notifyError(ex, sessionId);
      }
    } else if (intent.getAction().equals(REQUEST_STATE)) {
      Intent i = new Intent(EVENT_REPORTSTATE);
      
      synchronized (this) {
        i.putExtra(EVENT_REPORTSTATE_CONNECTED, reader != null);
        i.putExtra(SESSION_ID, sessionId);
        if (reader != null) {
          i.putExtra(EVENT_REPORTSTATE_DEVICENAME, reader.getDeviceAddress());
          i.putExtra(EVENT_REPORTSTATE_DISPLAYNAME, reader.getDeviceName());
          i.putExtra(EVENT_REPORTSTATE_DRIVERNAME, reader.getDriverName());
        }
      }
      
      sendBroadcast(i);
    } else if (intent.getAction().equals(REQUEST_CONFIG)) {
      Intent i = new Intent(EVENT_REPORT_CONFIG);
      
      int version = 0;
      try
      {
          version = this.getPackageManager().getPackageInfo(this.getPackageName(), 0).versionCode;
      }
      catch (NameNotFoundException e)
      {
          Log.w(LOG_NAME, e.getMessage());
      }
      
      i.putExtra(SESSION_ID, sessionId);
      i.putExtra(EVENT_REPORT_CONFIG_VERSION, version);
      i.putExtra(EVENT_REPORT_CONFIG_DRIVER_NAMES, getDriverNames());
      i.putExtra(EVENT_REPORT_CONFIG_DRIVER_DISPLAYNAMES, getDriverDisplayNames());
      
      sendBroadcast(i);
    } else {
      notifyError(new Exception(this.getString(R.string.bluetooth_unsupported)), sessionId);
    }
  }

  private synchronized void disconnectFromDevice(String sessionId)
  {
    String adr = "<null>"; 
    try
    {
      BluezDriverInterface reader = null;
      synchronized (m_readers) {
        if (sessionId != null && m_readers.containsKey(sessionId))
          reader = m_readers.get(sessionId);
      }
      
      if (reader != null) {
        adr = reader.getDeviceAddress();
        Log.d(LOG_NAME, "Disconnect requested");
        reader.stop();
      }
    }
    catch (Exception ex)
    {
          Log.e(LOG_NAME, "Error on disconnect from " + adr + ", message: " + ex.toString());
          notifyError(ex, sessionId);
    }
    finally
    {
      synchronized (m_readers) {
        if (sessionId != null && m_readers.containsKey(sessionId))
          m_readers.remove(sessionId);
      }
    }
  }
  
  private synchronized void connectToDevice(String address, String driver, String sessionId, boolean startnotification) {
    try {
      if (sessionId == null || sessionId.trim().length() == 0)
        throw new Exception("Invalid call, no session id specified, this is an API violation, please report to the app maker");
      if (driver == null || driver.trim().length() == 0)
        throw new Exception("Invalid call, no driver specified, this is an API violation, please report to the app maker");

      //The error message is slightly different here because it is possible for the user to activate the IME without selecting a device
      if (address == null || address.trim().length() == 0)
        throw new Exception("No device selected, please select a device");

      BluetoothAdapter blue = BluetoothAdapter.getDefaultAdapter();
      if (blue == null)
        throw new Exception(this.getString(R.string.bluetooth_unsupported));
      if (!blue.isEnabled())
        throw new Exception(this.getString(R.string.error_bluetooth_off));

      BluezDriverInterface reader = null;
      
      synchronized (m_readers) {
        if (sessionId != null && m_readers.containsKey(sessionId))
          reader = m_readers.get(sessionId);
      
        if (reader != null)
        {
          if (reader.isRunning() && address.equals(reader.getDeviceAddress()) && driver.toLowerCase().equals(reader.getDriverName()))
            return; //Already connected

          //Connect to other device, disconnect
          disconnectFromDevice(sessionId);
        }
        
        Intent connectingBroadcast = new Intent(EVENT_CONNECTING);
        connectingBroadcast.putExtra(EVENT_CONNECTING_ADDRESS, address);
        connectingBroadcast.putExtra(SESSION_ID, sessionId);
        sendBroadcast(connectingBroadcast);
  
        if (driver.toLowerCase().equals(ZeemoteReader.DRIVER_NAME.toLowerCase()))
          reader = new ZeemoteReader(address, sessionId, getApplicationContext(), startnotification);
        else if (driver.toLowerCase().equals(BGP100Reader.DRIVER_NAME.toLowerCase()))
          reader = new BGP100Reader(address, sessionId, getApplicationContext(), startnotification);
        else if (driver.toLowerCase().equals(PhonejoyReader.DRIVER_NAME.toLowerCase()))
          reader = new PhonejoyReader(address, sessionId, getApplicationContext(), startnotification);
        else if (driver.toLowerCase().equals(DataDumpReader.DRIVER_NAME.toLowerCase()))
          reader = new DataDumpReader(address, sessionId, getApplicationContext(), startnotification);
        else if (driver.toLowerCase().equals(PalmOneWirelessKeyboardReader.DRIVER_NAME.toLowerCase()))
          reader = new PalmOneWirelessKeyboardReader(address, sessionId, getApplicationContext(), startnotification);
        else if (driver.toLowerCase().equals(iControlPadReader.DRIVER_NAME.toLowerCase()))
          reader = new iControlPadReader(address, sessionId, getApplicationContext(), startnotification);
        else if (driver.toLowerCase().equals(WiimoteReader.DRIVER_NAME.toLowerCase()))
          reader = new WiimoteReader(address, sessionId, getApplicationContext(), startnotification);
        else if (driver.toLowerCase().equals(HIDKeyboard.DRIVER_NAME.toLowerCase()))
          reader = new HIDKeyboard(address, sessionId, getApplicationContext(), startnotification);
        else if (driver.toLowerCase().equals(iCadeReader.DRIVER_NAME.toLowerCase()))
          reader = new iCadeReader(address, sessionId, getApplicationContext(), startnotification);
        else if (driver.toLowerCase().equals(GameStopReader.DRIVER_NAME.toLowerCase()))
          reader = new GameStopReader(address, sessionId, getApplicationContext(), startnotification);
                else if (driver.toLowerCase().equals(HIDipega.DRIVER_NAME.toLowerCase()))
                    reader = new HIDipega(address, sessionId, getApplicationContext(), startnotification);
        else
          throw new Exception(String.format(this.getString(R.string.invalid_driver), driver));
        
        m_readers.put(sessionId, reader);
      }
      
      new Thread(reader).start();
    } catch (Exception ex) {
      notifyError(ex, sessionId);
    }
  }
  
  public String[] getDriverNames() {
    ArrayList<String> drivers = new ArrayList<String>(); 
    for(int i = 0; i < BASE_DRIVER_NAMES.length; i++)
      drivers.add(BASE_DRIVER_NAMES[i]);
    
    if (hasHIDSupport())
      for(int i = 0; i < HID_DRIVER_NAMES.length; i++)
        drivers.add(HID_DRIVER_NAMES[i]);
    
    return drivers.toArray(new String[drivers.size()]); 
  }
  public String[] getDriverDisplayNames() { 
    ArrayList<String> drivers = new ArrayList<String>(); 
    for(int i = 0; i < BASE_DRIVER_DISPLAYNAMES.length; i++)
      drivers.add(BASE_DRIVER_DISPLAYNAMES[i]);

    if (hasHIDSupport())
      for(int i = 0; i < HID_DRIVER_DISPLAYNAMES.length; i++)
        drivers.add(HID_DRIVER_DISPLAYNAMES[i]);

    return drivers.toArray(new String[drivers.size()]); 
  }
  
  public static String getDefaultDriverName() { return BASE_DRIVER_NAMES[0]; }

  private boolean hasHIDSupport() {
    if (!hasProbedForHID) {
      hasProbedForHID = true;
      supportsHID = false;
      try {      
        PackageInfo pi = this.getPackageManager().getPackageInfo("com.hexad.bluezime.hidenabler", PackageManager.GET_GIDS);
        supportsHID = pi != null;
      } catch (NameNotFoundException e) {
        
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    
    return supportsHID; 
  }
  
  private void notifyError(Exception ex, String sessionId) {
    Log.e(LOG_NAME, ex.toString());

    Intent errorBroadcast = new Intent(EVENT_ERROR);
    errorBroadcast.putExtra(EVENT_ERROR_SHORT, ex.getMessage());
    errorBroadcast.putExtra(EVENT_ERROR_FULL, ex.toString());
    errorBroadcast.putExtra(SESSION_ID, sessionId);
    sendBroadcast(errorBroadcast);
    
    disconnectFromDevice(sessionId);
  }
}




Java Source Code List

mobi.omegacentauri.p1keyboard.BGP100Reader.java
mobi.omegacentauri.p1keyboard.BluezDriverInterface.java
mobi.omegacentauri.p1keyboard.BluezForegroundService.java
mobi.omegacentauri.p1keyboard.BluezIMESettings.java
mobi.omegacentauri.p1keyboard.BluezIME.java
mobi.omegacentauri.p1keyboard.BluezService.java
mobi.omegacentauri.p1keyboard.ButtonConfiguration.java
mobi.omegacentauri.p1keyboard.DataDumpReader.java
mobi.omegacentauri.p1keyboard.DeviceScanActivity.java
mobi.omegacentauri.p1keyboard.FutureKeyCodes.java
mobi.omegacentauri.p1keyboard.GameStopReader.java
mobi.omegacentauri.p1keyboard.HIDKeyboard.java
mobi.omegacentauri.p1keyboard.HIDReaderBase.java
mobi.omegacentauri.p1keyboard.HIDipega.java
mobi.omegacentauri.p1keyboard.ImprovedBluetoothDevice.java
mobi.omegacentauri.p1keyboard.PalmOneWirelessKeyboardReader.java
mobi.omegacentauri.p1keyboard.PhonejoyReader.java
mobi.omegacentauri.p1keyboard.Preferences.java
mobi.omegacentauri.p1keyboard.RfcommReader.java
mobi.omegacentauri.p1keyboard.WiimoteReader.java
mobi.omegacentauri.p1keyboard.ZeemoteReader.java
mobi.omegacentauri.p1keyboard.iCadeReader.java
mobi.omegacentauri.p1keyboard.iControlPadReader.java