private DeviceSupport createBTDeviceSupport(String deviceAddress) throws GBException {
    if (mBtAdapter != null && mBtAdapter.isEnabled()) {
      GBDevice gbDevice = null;
      DeviceSupport deviceSupport = null;

      try {
        BluetoothDevice btDevice = mBtAdapter.getRemoteDevice(deviceAddress);
        if (btDevice.getName() == null
            || btDevice
                .getName()
                .startsWith("MI")) { // FIXME: workaround for Miband not being paired
          gbDevice = new GBDevice(deviceAddress, "MI", DeviceType.MIBAND);
          deviceSupport =
              new ServiceDeviceSupport(
                  new MiBandSupport(),
                  EnumSet.of(
                      ServiceDeviceSupport.Flags.THROTTLING,
                      ServiceDeviceSupport.Flags.BUSY_CHECKING));
        } else if (btDevice.getName().indexOf("Pebble") == 0) {
          gbDevice = new GBDevice(deviceAddress, btDevice.getName(), DeviceType.PEBBLE);
          deviceSupport =
              new ServiceDeviceSupport(
                  new PebbleSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
        }
        if (deviceSupport != null) {
          deviceSupport.setContext(gbDevice, mBtAdapter, mContext);
          return deviceSupport;
        }
      } catch (Exception e) {
        throw new GBException(mContext.getString(R.string.cannot_connect_bt_address_invalid_, e));
      }
    }
    return null;
  }
 private DeviceSupport createTCPDeviceSupport(String deviceAddress) throws GBException {
   try {
     GBDevice gbDevice =
         new GBDevice(deviceAddress, "Pebble qemu", DeviceType.PEBBLE); // FIXME, do not hardcode
     DeviceSupport deviceSupport =
         new ServiceDeviceSupport(
             new PebbleSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
     deviceSupport.setContext(gbDevice, mBtAdapter, mContext);
     return deviceSupport;
   } catch (Exception e) {
     throw new GBException("cannot connect to " + deviceAddress, e); // FIXME: localize
   }
 }
 private DeviceSupport createClassNameDeviceSupport(String className) throws GBException {
   try {
     Class<?> deviceSupportClass = Class.forName(className);
     Constructor<?> constructor = deviceSupportClass.getConstructor();
     DeviceSupport support = (DeviceSupport) constructor.newInstance();
     // has to create the device itself
     support.setContext(null, null, mContext);
     return support;
   } catch (ClassNotFoundException e) {
     return null; // not a class, or not known at least
   } catch (Exception e) {
     throw new GBException("Error creating DeviceSupport instance for " + className, e);
   }
 }
 @Override
 public void onReceive(Context context, Intent intent) {
   String action = intent.getAction();
   if (action.equals(GBDevice.ACTION_DEVICE_CHANGED)) {
     GBDevice device = intent.getParcelableExtra("device");
     if (mGBDevice.equals(device)) {
       mGBDevice = device;
       boolean enableReceivers =
           mDeviceSupport != null
               && (mDeviceSupport.useAutoConnect() || mGBDevice.isConnected());
       GB.setReceiversEnableState(enableReceivers, context);
       GB.updateNotification(
           mGBDevice.getName() + " " + mGBDevice.getStateString(), context);
     }
   }
 }
  @Override
  public void onDestroy() {
    LOG.debug("BluetoothCommunicationService is being destroyed");
    super.onDestroy();

    LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
    GB.setReceiversEnableState(false, this); // disable BroadcastReceivers

    if (mDeviceSupport != null) {
      mDeviceSupport.dispose();
    }
    NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    nm.cancel(
        GB.NOTIFICATION_ID); // need to do this because the updated notification wont be cancelled
    // when service stops
  }
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {

    if (intent == null) {
      LOG.info("no intent");
      return START_NOT_STICKY;
    }

    String action = intent.getAction();
    boolean pair = intent.getBooleanExtra(EXTRA_PERFORM_PAIR, false);

    if (action == null) {
      LOG.info("no action");
      return START_NOT_STICKY;
    }

    LOG.debug("Service startcommand: " + action);

    if (!mStarted && !action.equals(ACTION_START)) {
      // using the service before issuing ACTION_START
      LOG.info("Must start service with " + ACTION_START + " before using it: " + action);
      return START_NOT_STICKY;
    }

    if (mStarted && action.equals(ACTION_START)) {
      // using ACTION_START when the service has already been started
      return START_STICKY;
    }

    if (!action.equals(ACTION_START) && !action.equals(ACTION_CONNECT)) {
      if (mDeviceSupport == null || (!isConnected() && !mDeviceSupport.useAutoConnect())) {
        // trying to send notification without valid Bluetooth connection
        if (mGBDevice != null) {
          // at least send back the current device state
          mGBDevice.sendDeviceUpdateIntent(this);
        }
        return START_STICKY;
      }
    }

    switch (action) {
      case ACTION_CONNECT:
        // Check the system status
        BluetoothAdapter mBtAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBtAdapter == null) {
          Toast.makeText(this, R.string.bluetooth_is_not_supported_, Toast.LENGTH_SHORT).show();
        } else if (!mBtAdapter.isEnabled()) {
          Toast.makeText(this, R.string.bluetooth_is_disabled_, Toast.LENGTH_SHORT).show();
        } else {
          String btDeviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS);
          SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
          sharedPrefs.edit().putString("last_device_address", btDeviceAddress).apply();

          if (btDeviceAddress != null && !isConnected() && !isConnecting()) {
            if (mDeviceSupport != null) {
              mDeviceSupport.dispose();
              mDeviceSupport = null;
            }
            try {
              BluetoothDevice btDevice = mBtAdapter.getRemoteDevice(btDeviceAddress);
              if (btDevice.getName() == null
                  || btDevice
                      .getName()
                      .equals("MI")) { // FIXME: workaround for Miband not being paired
                mGBDevice = new GBDevice(btDeviceAddress, "MI", DeviceType.MIBAND);
                mDeviceSupport = new ServiceDeviceSupport(new MiBandSupport());
              } else if (btDevice.getName().indexOf("Pebble") == 0) {
                mGBDevice = new GBDevice(btDeviceAddress, btDevice.getName(), DeviceType.PEBBLE);
                mDeviceSupport = new ServiceDeviceSupport(new PebbleSupport());
              }
              if (mDeviceSupport != null) {
                mDeviceSupport.initialize(mGBDevice, mBtAdapter, this);
                if (pair) {
                  mDeviceSupport.pair();
                } else {
                  mDeviceSupport.connect();
                }
              }
            } catch (Exception e) {
              Toast.makeText(this, R.string.cannot_connect_bt_address_invalid_, Toast.LENGTH_SHORT)
                  .show();
              e.printStackTrace();
            }
          }
        }
        break;
      case ACTION_NOTIFICATION_GENERIC:
        {
          String title = intent.getStringExtra("notification_title");
          String body = intent.getStringExtra("notification_body");
          mDeviceSupport.onGenericNotification(title, body);
          break;
        }
      case ACTION_NOTIFICATION_SMS:
        {
          String sender = intent.getStringExtra("notification_sender");
          String body = intent.getStringExtra("notification_body");
          String senderName = getContactDisplayNameByNumber(sender);
          mDeviceSupport.onSMS(senderName, body);
          break;
        }
      case ACTION_NOTIFICATION_EMAIL:
        {
          String sender = intent.getStringExtra("notification_sender");
          String subject = intent.getStringExtra("notification_subject");
          String body = intent.getStringExtra("notification_body");
          mDeviceSupport.onEmail(sender, subject, body);
          break;
        }
      case ACTION_REBOOT:
        {
          mDeviceSupport.onReboot();
          break;
        }
      case ACTION_FETCH_ACTIVITY_DATA:
        {
          mDeviceSupport.onFetchActivityData();
          break;
        }
      case ACTION_DISCONNECT:
        {
          mDeviceSupport.dispose();
          mDeviceSupport = null;
          break;
        }
      case ACTION_FIND_DEVICE:
        {
          boolean start = intent.getBooleanExtra("find_start", false);
          mDeviceSupport.onFindDevice(start);
          break;
        }
      case ACTION_CALLSTATE:
        GBCommand command = GBCommand.values()[intent.getIntExtra("call_command", 0)]; // UGLY

        String phoneNumber = intent.getStringExtra("call_phonenumber");
        String callerName = null;
        if (phoneNumber != null) {
          callerName = getContactDisplayNameByNumber(phoneNumber);
        }
        mDeviceSupport.onSetCallState(phoneNumber, callerName, command);
        break;
      case ACTION_SETTIME:
        mDeviceSupport.onSetTime(-1);
        break;
      case ACTION_SETMUSICINFO:
        String artist = intent.getStringExtra("music_artist");
        String album = intent.getStringExtra("music_album");
        String track = intent.getStringExtra("music_track");
        mDeviceSupport.onSetMusicInfo(artist, album, track);
        break;
      case ACTION_REQUEST_VERSIONINFO:
        if (mGBDevice != null && mGBDevice.getFirmwareVersion() == null) {
          mDeviceSupport.onFirmwareVersionReq();
        } else {
          mGBDevice.sendDeviceUpdateIntent(this);
        }
        break;
      case ACTION_REQUEST_APPINFO:
        mDeviceSupport.onAppInfoReq();
        break;
      case ACTION_REQUEST_SCREENSHOT:
        mDeviceSupport.onScreenshotReq();
        break;
      case ACTION_STARTAPP:
        UUID uuid = UUID.fromString(intent.getStringExtra("app_uuid"));
        mDeviceSupport.onAppStart(uuid);
        break;
      case ACTION_DELETEAPP:
        uuid = UUID.fromString(intent.getStringExtra("app_uuid"));
        mDeviceSupport.onAppDelete(uuid);
        break;
      case ACTION_INSTALL_PEBBLEAPP:
        String uriString = intent.getStringExtra("app_uri");
        if (uriString != null) {
          LOG.info("will try to install app");
          mDeviceSupport.onInstallApp(Uri.parse(uriString));
        }
        break;
      case ACTION_START:
        startForeground(
            GB.NOTIFICATION_ID,
            GB.createNotification(getString(R.string.gadgetbridge_running), this));
        mStarted = true;
        break;
    }

    return START_STICKY;
  }