public static void setSilentMode(boolean enabled) {
    silentMode = enabled;
    Idle.updateIdle(context, true);

    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
    Editor editor = sharedPreferences.edit();
    editor.putBoolean("SilentMode", silentMode);
    editor.commit();
  }
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {

          if (Preferences.logging) Log.d(MetaWatch.TAG, "onSharedPreferenceChanged " + key);

          MetaWatchService.loadPreferences(context);

          if (key.contains("Weather")) {
            Monitors.restart(context);
          }

          if (key.contains("Idle") || key.contains(".app_enabled")) {
            Idle.reset(context);
          }

          if (key.contains("Widgets") || (key.equals("SilentMode"))) {
            Idle.updateIdle(context, true);
          }
        }
  void readFromDevice() {

    if (MetaWatchService.fakeWatch) {
      try {
        Thread.sleep(10000);
      } catch (InterruptedException e) {
      }
      return;
    }

    try {
      byte[] bytes = new byte[256];
      if (Preferences.logging) Log.d(MetaWatch.TAG, "before blocking read");
      // Do a proper read loop
      int haveread = 0;
      int lengthtoread = 4;
      while ((lengthtoread - haveread) != 0) {
        haveread += inputStream.read(bytes, haveread, lengthtoread - haveread);
        if (haveread > 1) {
          lengthtoread = bytes[1];
        }
      }

      wakeLock.acquire(5000);

      // print received
      String str = "received: ";
      int len = (bytes[1] & 0xFF);
      if (Preferences.logging) Log.d(MetaWatch.TAG, "packet length: " + len);

      for (int i = 0; i < len; i++) {
        // str+= Byte.toString(bytes[i]) + ", ";
        str += "0x" + Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1) + ", ";
      }
      if (Preferences.logging) Log.d(MetaWatch.TAG, str);
      /*
       * switch (bytes[2]) { case eMessageType.GetDeviceTypeResponse.msg:
       * if (Preferences.logging) Log.d(MetaWatch.TAG, "received: device type response"); break;
       * case eMessageType.NvalOperationResponseMsg.msg:
       * if (Preferences.logging) Log.d(MetaWatch.TAG, "received: nval response"); break; case
       * eMessageType.StatusChangeEvent.msg: if (Preferences.logging) Log.d(MetaWatch.TAG,
       * "received: status change event"); break; }
       */
      /*
       * if (bytes[2] == 0x31) { // nval response if (bytes[3] == 0x00) //
       * success if (bytes[4] == 0x00) // set to 12 hour format
       * Protocol.setNvalTime(true); }
       */
      if (bytes[2] == eMessageType.NvalOperationResponseMsg.msg) {
        if (Preferences.logging)
          Log.d(MetaWatch.TAG, "MetaWatchService.readFromDevice(): NvalOperationResponseMsg");
        // Do something here?
      } else if (bytes[2] == eMessageType.StatusChangeEvent.msg) { // status
        // change
        // event
        if (Preferences.logging)
          Log.d(MetaWatch.TAG, "MetaWatchService.readFromDevice(): status change");
        if (bytes[4] == 0x01) {
          if (Preferences.logging)
            Log.d(MetaWatch.TAG, "MetaWatchService.readFromDevice(): mode changed");
          synchronized (Notification.modeChanged) {
            Notification.modeChanged.notify();
          }
        } else if (bytes[4] == 0x11) {
          if (Preferences.logging)
            Log.d(MetaWatch.TAG, "MetaWatchService.readFromDevice(): scroll request notification");

          synchronized (Notification.scrollRequest) {
            Notification.scrollRequest.notify();
          }
        } else if (bytes[4] == 0x10) {
          if (Preferences.logging)
            Log.d(MetaWatch.TAG, "MetaWatchService.readFromDevice(): scroll complete.");
        }
      } else if (bytes[2] == eMessageType.ButtonEventMsg.msg) { // button
        // press
        if (Preferences.logging)
          Log.d(MetaWatch.TAG, "MetaWatchService.readFromDevice(): button event");
        pressedButton(bytes[3] & 0xFF); //
      } else if (bytes[2] == eMessageType.GetDeviceTypeResponse.msg) { // device
        // type
        if (bytes[4] == 1 || bytes[4] == 4) {
          watchType = WatchType.ANALOG;
          if (Preferences.logging)
            Log.d(
                MetaWatch.TAG,
                "MetaWatchService.readFromDevice(): device type response; analog watch");

          if (watchState == WatchStates.OFF || watchState == WatchStates.IDLE) {
            Idle.toIdle(this);
            Idle.updateIdle(this, true);
          }

          SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
          boolean displaySplash = sharedPreferences.getBoolean("DisplaySplashScreen", true);
          if (displaySplash) {
            Protocol.sendOledBitmap(
                Utils.getBitmap(this, "splash_16_0.bmp"),
                MetaWatchService.WatchBuffers.NOTIFICATION,
                0);
            Protocol.sendOledBitmap(
                Utils.getBitmap(this, "splash_16_1.bmp"),
                MetaWatchService.WatchBuffers.NOTIFICATION,
                1);
          }

        } else {
          watchType = WatchType.DIGITAL;
          if (Preferences.logging)
            Log.d(
                MetaWatch.TAG,
                "MetaWatchService.readFromDevice(): device type response; digital watch");

          Protocol.configureMode();

          if (watchState == WatchStates.OFF || watchState == WatchStates.IDLE) {
            Idle.toIdle(this);
            Idle.updateIdle(this, true);
          }

          SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
          boolean displaySplash = sharedPreferences.getBoolean("DisplaySplashScreen", true);
          if (displaySplash) {
            Notification.addBitmapNotification(
                this,
                Utils.getBitmap(this, "splash.png"),
                new VibratePattern(false, 0, 0, 0),
                10000,
                "Splash");
          }

          Protocol.queryNvalTime();
        }

        SharedPreferences sharedPreferences =
            PreferenceManager.getDefaultSharedPreferences(context);

        /* Notify watch on connection if requested. */
        boolean notifyOnConnect = sharedPreferences.getBoolean("NotifyWatchOnConnect", false);
        if (Preferences.logging)
          Log.d(MetaWatch.TAG, "MetaWatchService.connect(): notifyOnConnect=" + notifyOnConnect);
        if (notifyOnConnect) {
          NotificationBuilder.createOtherNotification(
              context,
              null,
              "MetaWatch",
              getResources().getString(R.string.connection_connected),
              1);
        }

        Idle.activateButtons(this);

      } else if (bytes[2] == eMessageType.ReadBatteryVoltageResponse.msg) {
        boolean powerGood = bytes[4] > 0;
        boolean batteryCharging = bytes[5] > 0;
        float batterySense = (((int) bytes[7] << 8) + (int) bytes[6]) / 1000.0f;
        float batteryAverage = (((int) bytes[9] << 8) + (int) bytes[8]) / 1000.0f;
        if (Preferences.logging)
          Log.d(
              MetaWatch.TAG,
              "MetaWatchService.readFromDevice(): received battery voltage response."
                  + " power_good="
                  + powerGood
                  + " battery_charging="
                  + batteryCharging
                  + " battery_sense="
                  + batterySense
                  + " battery_average="
                  + batteryAverage);
        String voltageFrequencyString =
            PreferenceManager.getDefaultSharedPreferences(this)
                .getString("collectWatchVoltage", "0");
        final int voltageFrequency = Integer.parseInt(voltageFrequencyString);
        if (voltageFrequency > 0) {
          File sdcard = Environment.getExternalStorageDirectory();
          File csv = new File(sdcard, "metawatch_voltage.csv");
          boolean fileExists = csv.exists();
          FileWriter fw = new FileWriter(csv, true);
          if (fileExists == false) {
            fw.write("Date,Sense,Average\n");
          }
          Date date = new Date();
          fw.write("\"" + date.toString() + "\"," + batterySense + "," + batteryAverage + "\n");
          fw.flush();
          fw.close();
        }
      } else if (bytes[2] == eMessageType.ReadLightSensorResponse.msg) {
        float lightSense = (((int) bytes[1] << 8) + (int) bytes[0]) / 1000.0f;
        float lightAverage = (((int) bytes[3] << 8) + (int) bytes[2]) / 1000.0f;
        if (Preferences.logging)
          Log.d(
              MetaWatch.TAG,
              "MetaWatchService.readFromDevice(): received light sensor response."
                  + " light_sense="
                  + lightSense
                  + " light_average="
                  + lightAverage);
      } else if (bytes[2] == eMessageType.GetRealTimeClockResponse.msg) {
        long timeNow = System.currentTimeMillis();
        long roundTrip = timeNow - Monitors.getRTCTimestamp;

        if (Preferences.logging)
          Log.d(
              MetaWatch.TAG,
              "MetaWatchService.readFromDevice(): received rtc response."
                  + " round trip= "
                  + roundTrip);

        Monitors.rtcOffset = (int) (roundTrip / 2000);

        Protocol.sendRtcNow(context);

      } else {
        if (Preferences.logging)
          Log.d(
              MetaWatch.TAG,
              "MetaWatchService.readFromDevice(): Unknown message : 0x"
                  + Integer.toString((bytes[2] & 0xff) + 0x100, 16).substring(1)
                  + ", ");
      }

    } catch (IOException e) {
      if (Preferences.logging) Log.d(MetaWatch.TAG, e.toString());
      resetConnection();
    } catch (ArrayIndexOutOfBoundsException e) {
      if (Preferences.logging) Log.d(MetaWatch.TAG, e.toString());
      resetConnection();
    } finally {
      if (wakeLock != null && wakeLock.isHeld()) {
        wakeLock.release();
      }
    }
  }
  @TargetApi(10)
  void connect(Context context) {

    try {

      MetaWatchService.fakeWatch = false;
      if (Preferences.watchMacAddress.equals("DIGITAL")) {
        MetaWatchService.fakeWatch = true;
        MetaWatchService.watchType = MetaWatchService.WatchType.DIGITAL;
      }
      if (Preferences.watchMacAddress.equals("ANALOG")) {
        MetaWatchService.fakeWatch = true;
        MetaWatchService.watchType = MetaWatchService.WatchType.ANALOG;
      }

      if (Preferences.logging)
        Log.d(MetaWatch.TAG, "Remote device address: " + Preferences.watchMacAddress);
      if (!Preferences.loaded) loadPreferences(context);

      if (!MetaWatchService.fakeWatch) {

        if (bluetoothAdapter == null) {
          sendToast(getResources().getString(R.string.error_bluetooth_not_supported));
          return;
        } else if (!bluetoothAdapter.isEnabled()) {
          sendToast(getResources().getString(R.string.error_bluetooth_not_enabled));
          return;
        }

        wakeLock.acquire(5000);

        BluetoothDevice bluetoothDevice =
            bluetoothAdapter.getRemoteDevice(Preferences.watchMacAddress);

        if (Preferences.skipSDP) {
          Method method =
              bluetoothDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
          bluetoothSocket = (BluetoothSocket) method.invoke(bluetoothDevice, 1);
        } else {
          UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

          int currentapiVersion = android.os.Build.VERSION.SDK_INT;

          if (Preferences.insecureBtSocket
              && currentapiVersion >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
            bluetoothSocket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(uuid);
          } else {
            bluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(uuid);
          }
        }

        bluetoothAdapter.cancelDiscovery();
        bluetoothSocket.connect();

        inputStream = bluetoothSocket.getInputStream();
        outputStream = bluetoothSocket.getOutputStream();
      }

      connectionState = ConnectionState.CONNECTED;
      updateNotification();

      Protocol.startProtocolSender();

      // RM: This is disabled for now, as it seems to confuse the watch fw (3.1.0S tested)
      // and get it into a state where it won't accept any date/time format updates :-S

      // if( Preferences.autoClockFormat )
      //	Protocol.setTimeDateFormat(this);

      Protocol.getRealTimeClock();
      Protocol.getDeviceType();

      Notification.startNotificationSender(this);

      Idle.updateIdle(this, true);

    } catch (IOException ioexception) {
      if (Preferences.logging) Log.d(MetaWatch.TAG, ioexception.toString());
    } catch (SecurityException e) {
      if (Preferences.logging) Log.d(MetaWatch.TAG, e.toString());
    } catch (NoSuchMethodException e) {
      if (Preferences.logging) Log.d(MetaWatch.TAG, e.toString());
    } catch (IllegalArgumentException e) {
      if (Preferences.logging) Log.d(MetaWatch.TAG, e.toString());
    } catch (IllegalAccessException e) {
      if (Preferences.logging) Log.d(MetaWatch.TAG, e.toString());
    } catch (InvocationTargetException e) {
      if (Preferences.logging) Log.d(MetaWatch.TAG, e.toString());
    } catch (NullPointerException e) {
      if (Preferences.logging) Log.d(MetaWatch.TAG, e.toString());
    } finally {
      if (wakeLock != null && wakeLock.isHeld()) {
        wakeLock.release();
      }
    }

    return;
  }
  void pressedButton(int button) {
    if (Preferences.logging) Log.d(MetaWatch.TAG, "button code: " + Integer.toString(button));

    wakeLock.acquire(10000);

    try {

      if (button > 0 && Preferences.hapticFeedback) Protocol.vibrate(5, 5, 2);

      if (Preferences.logging)
        Log.d(MetaWatch.TAG, "MetaWatchService.pressedButton(): watchState=" + watchState);
      switch (watchState) {
        case WatchStates.IDLE:
          {
            int idleAppButton = Idle.appButtonPressed(this, button);
            if (idleAppButton == ApplicationBase.BUTTON_NOT_USED) {

              switch (button) {
                case Idle.QUICK_BUTTON:
                  Idle.quickButtonAction(this);
                  break;

                case Idle.IDLE_NEXT_PAGE:
                  if (MetaWatchService.watchType == MetaWatchService.WatchType.DIGITAL) {
                    Idle.nextPage(this);
                    Idle.updateIdle(this, true);
                  }
                  break;

                case Idle.TOGGLE_SILENT:
                  MetaWatchService.setSilentMode(!silentMode);
                  Protocol.vibrate(500, 500, 2);
                  break;

                case Idle.IDLE_OLED_DISPLAY:
                  long time = System.currentTimeMillis();

                  if (time - lastOledCrownPress < 1000 * 5) {
                    Idle.nextPage(this);
                    Idle.updateIdle(this, true);
                  }

                  lastOledCrownPress = time;
                  Idle.sendOledIdle(this);
                  break;

                case Application.TOGGLE_APP:
                  Application.toggleApp(context, Idle.getCurrentApp());
                  break;
              }
            } else if (idleAppButton != ApplicationBase.BUTTON_USED_DONT_UPDATE) {
              Idle.updateIdle(this, false);
              if (MetaWatchService.watchType == MetaWatchService.WatchType.ANALOG)
                Idle.sendOledIdle(this);
            }
            break;
          }

        case WatchStates.APPLICATION:
          Application.buttonPressed(this, button);
          break;

        case WatchStates.NOTIFICATION:
          switch (button) {
            case Call.CALL_ANSWER:
              MediaControl.answerCall(this);
              break;
            case Call.CALL_DISMISS:
              MediaControl.ignoreCall(this);
              break;
            case Call.CALL_MENU:
              ActionManager.displayCallActions(this);
              break;
            default:
              Notification.buttonPressed(button);
              break;
          }
          break;
      }

    } finally {
      if (wakeLock != null && wakeLock.isHeld()) {
        wakeLock.release();
      }
    }
  }