react-native landscape mode Orientation - react-native

Im still beginner and here is one page that I want it to display with landscape mode when I open up the page. I installed react-native-orientation, but im not sure how I can use this.
I want landscape mode when I open the app, so I believe that I should set Orientation when I use, componentWillMount(){
Orientation
}
but im not sure how to set it up... could anyone tell me how?

Try Following package may be help you.
react-native-orientation

only this one line add on your project in your
android:screenOrientation="landscape"
android->app->src->main->AndroidManifest.xml
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:screenOrientation="landscape"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

I came across the same issue instead of using third party module I created my own.
My React Native Module:
public class OrientationHelperModule extends ReactContextBaseJavaModule {
private static final String TAG = OrientationHelperModule.class.getSimpleName();
private static final String MODULE_NAME = "OrientationHelperModule";
private final ReactApplicationContext reactAppContext;
#Override
public String getName() {
return MODULE_NAME;
}
public OrientationHelperModule(ReactApplicationContext reactAppContext) {
super(reactAppContext);
this.reactAppContext = reactAppContext;
}
#ReactMethod
public void lockLandscape() {
OrientationUtils.lockOrientationLandscape(getCurrentActivity());
}
#ReactMethod
public void unlockOrientation() {
OrientationUtils.unlockOrientation(getCurrentActivity());
}
#ReactMethod
public void lockPortrait() {
OrientationUtils.lockOrientationPortrait(getCurrentActivity());
}
}
The Helper class to handle orientation lock
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Build;
import android.view.Surface;
import android.view.WindowManager;
/* * This class is used to lock orientation of Android app in any Android devices
*/
public class OrientationUtils {
private OrientationUtils() {
}
/**
* Locks the device window in landscape mode.
*/
public static void lockOrientationLandscape(Activity activity) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
}
/**
* Locks the device window in portrait mode.
*/
public static void lockOrientationPortrait(Activity activity) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
/**
* Locks the device window in actual screen mode.
*/
public static void lockOrientation(Activity activity) {
final int orientation = activity.getResources().getConfiguration().orientation;
final int rotation = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
.getRotation();
// Copied from Android docs, since we don't have these values in Froyo
// 2.2
int SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8;
int SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9;
// Build.VERSION.SDK_INT <= Build.VERSION_CODES.FROYO
if (!(Build.VERSION.SDK_INT <= Build.VERSION_CODES.FROYO)) {
SCREEN_ORIENTATION_REVERSE_LANDSCAPE = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
SCREEN_ORIENTATION_REVERSE_PORTRAIT = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
}
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90) {
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
} else if (rotation == Surface.ROTATION_180 || rotation == Surface.ROTATION_270) {
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
}
}
}
/**
* Unlocks the device window in user defined screen mode.
*/
public static void unlockOrientation(Activity activity) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
}
}
Import it in React Native
'use strict';
import { NativeModules } from 'react-native';
module.exports = NativeModules.OrientationHelperModule;
Import OrientationHelperModule in your component
import OrientationHelperModule from './src/modules/OrientationHelperModule'
And use it to lock orientation
componentDidMount = () => {
OrientationHelperModule.lockLandscape();
}

Related

How to turn on flash in picture mode

[SOLVED]
After searching for an answer, I didn't find a solution for turning on the flash when in picture mode.
The app opens the camera in the background, and continulsy processes the pictures and detects objects, but the phone is located in a container which doesn't have light there, thus I need to make sure the flash is always opened.
There can be other approaches I'm considering as well and I'm not sure how to get these approaches to work also:
Switch to Video Mode. (Because I'm processing the pictures of the camera preview anyway, and in video mode the flash mode can work w/o recording a vide).
Set the camera default app to different app which supports image preview with flash when tapping on screen (I'll need to figure out how to switch to different app and how to simulate tapping, maybe even with another device which is connected to the app w/ bluetooth and sends clicks).
Override camera's API and make sure the Flash can be on, or just disabled and let another app turn on the flash.
This doesn't seem to work: (in the last code block)
Camera.Parameters parameters = camera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
Solution 1 or 3 should be ideal, any ideas how to make it work? This is the code I'm using:
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.ImageReader;
import android.media.ImageReader.OnImageAvailableListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.text.TextUtils;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import org.tensorflow.lite.examples.classification.customview.AutoFitTextureView;
import org.tensorflow.lite.examples.classification.env.Logger;
public class CameraConnectionFragment extends Fragment {
private static final Logger LOGGER = new Logger();
/**
* The camera preview size will be chosen to be the smallest frame by pixel size capable of
* containing a DESIRED_SIZE x DESIRED_SIZE square.
*/
private static final int MINIMUM_PREVIEW_SIZE = 320;
/** Conversion from screen rotation to JPEG orientation. */
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private static final String FRAGMENT_DIALOG = "dialog";
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
/** A {#link Semaphore} to prevent the app from exiting before closing the camera. */
private final Semaphore cameraOpenCloseLock = new Semaphore(1);
/** A {#link OnImageAvailableListener} to receive frames as they are available. */
private final OnImageAvailableListener imageListener;
/** The input size in pixels desired by TensorFlow (width and height of a square bitmap). */
private final Size inputSize;
/** The layout identifier to inflate for this Fragment. */
private final int layout;
private final ConnectionCallback cameraConnectionCallback;
private final CameraCaptureSession.CaptureCallback captureCallback =
new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureProgressed(
final CameraCaptureSession session,
final CaptureRequest request,
final CaptureResult partialResult) {}
#Override
public void onCaptureCompleted(
final CameraCaptureSession session,
final CaptureRequest request,
final TotalCaptureResult result) {}
};
/** ID of the current {#link CameraDevice}. */
private String cameraId;
/** An {#link AutoFitTextureView} for camera preview. */
private AutoFitTextureView textureView;
/** A {#link CameraCaptureSession } for camera preview. */
private CameraCaptureSession captureSession;
/** A reference to the opened {#link CameraDevice}. */
private CameraDevice cameraDevice;
/** The rotation in degrees of the camera sensor from the display. */
private Integer sensorOrientation;
/** The {#link Size} of camera preview. */
private Size previewSize;
/** An additional thread for running tasks that shouldn't block the UI. */
private HandlerThread backgroundThread;
/** A {#link Handler} for running tasks in the background. */
private Handler backgroundHandler;
/**
* {#link TextureView.SurfaceTextureListener} handles several lifecycle events on a {#link
* TextureView}.
*/
private final TextureView.SurfaceTextureListener surfaceTextureListener =
new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(
final SurfaceTexture texture, final int width, final int height) {
openCamera(width, height);
}
#Override
public void onSurfaceTextureSizeChanged(
final SurfaceTexture texture, final int width, final int height) {
configureTransform(width, height);
}
#Override
public boolean onSurfaceTextureDestroyed(final SurfaceTexture texture) {
return true;
}
#Override
public void onSurfaceTextureUpdated(final SurfaceTexture texture) {}
};
/** An {#link ImageReader} that handles preview frame capture. */
private ImageReader previewReader;
/** {#link CaptureRequest.Builder} for the camera preview */
private CaptureRequest.Builder previewRequestBuilder;
/** {#link CaptureRequest} generated by {#link #previewRequestBuilder} */
private CaptureRequest previewRequest;
/** {#link CameraDevice.StateCallback} is called when {#link CameraDevice} changes its state. */
private final CameraDevice.StateCallback stateCallback =
new CameraDevice.StateCallback() {
#Override
public void onOpened(final CameraDevice cd) {
// This method is called when the camera is opened. We start camera preview here.
cameraOpenCloseLock.release();
cameraDevice = cd;
createCameraPreviewSession();
}
#Override
public void onDisconnected(final CameraDevice cd) {
cameraOpenCloseLock.release();
cd.close();
cameraDevice = null;
}
#Override
public void onError(final CameraDevice cd, final int error) {
cameraOpenCloseLock.release();
cd.close();
cameraDevice = null;
final Activity activity = getActivity();
if (null != activity) {
activity.finish();
}
}
};
#SuppressLint("ValidFragment")
private CameraConnectionFragment(
final ConnectionCallback connectionCallback,
final OnImageAvailableListener imageListener,
final int layout,
final Size inputSize) {
this.cameraConnectionCallback = connectionCallback;
this.imageListener = imageListener;
this.layout = layout;
this.inputSize = inputSize;
}
/**
* Given {#code choices} of {#code Size}s supported by a camera, chooses the smallest one whose
* width and height are at least as large as the minimum of both, or an exact match if possible.
*
* #param choices The list of sizes that the camera supports for the intended output class
* #param width The minimum desired width
* #param height The minimum desired height
* #return The optimal {#code Size}, or an arbitrary one if none were big enough
*/
protected static Size chooseOptimalSize(final Size[] choices, final int width, final int height) {
final int minSize = Math.max(Math.min(width, height), MINIMUM_PREVIEW_SIZE);
final Size desiredSize = new Size(width, height);
// Collect the supported resolutions that are at least as big as the preview Surface
boolean exactSizeFound = false;
final List<Size> bigEnough = new ArrayList<Size>();
final List<Size> tooSmall = new ArrayList<Size>();
for (final Size option : choices) {
if (option.equals(desiredSize)) {
// Set the size but don't return yet so that remaining sizes will still be logged.
exactSizeFound = true;
}
if (option.getHeight() >= minSize && option.getWidth() >= minSize) {
bigEnough.add(option);
} else {
tooSmall.add(option);
}
}
LOGGER.i("Desired size: " + desiredSize + ", min size: " + minSize + "x" + minSize);
LOGGER.i("Valid preview sizes: [" + TextUtils.join(", ", bigEnough) + "]");
LOGGER.i("Rejected preview sizes: [" + TextUtils.join(", ", tooSmall) + "]");
if (exactSizeFound) {
LOGGER.i("Exact size match found.");
return desiredSize;
}
// Pick the smallest of those, assuming we found any
if (bigEnough.size() > 0) {
final Size chosenSize = Collections.min(bigEnough, new CompareSizesByArea());
LOGGER.i("Chosen size: " + chosenSize.getWidth() + "x" + chosenSize.getHeight());
return chosenSize;
} else {
LOGGER.e("Couldn't find any suitable preview size");
return choices[0];
}
}
public static CameraConnectionFragment newInstance(
final ConnectionCallback callback,
final OnImageAvailableListener imageListener,
final int layout,
final Size inputSize) {
return new CameraConnectionFragment(callback, imageListener, layout, inputSize);
}
/**
* Shows a {#link Toast} on the UI thread.
*
* #param text The message to show
*/
private void showToast(final String text) {
final Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(
new Runnable() {
#Override
public void run() {
Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
}
});
}
}
#Override
public View onCreateView(
final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return inflater.inflate(layout, container, false);
}
#Override
public void onViewCreated(final View view, final Bundle savedInstanceState) {
textureView = (AutoFitTextureView) view.findViewById(R.id.texture);
}
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onResume() {
super.onResume();
startBackgroundThread();
// When the screen is turned off and turned back on, the SurfaceTexture is already
// available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
// a camera and start preview from here (otherwise, we wait until the surface is ready in
// the SurfaceTextureListener).
if (textureView.isAvailable()) {
openCamera(textureView.getWidth(), textureView.getHeight());
} else {
textureView.setSurfaceTextureListener(surfaceTextureListener);
}
}
#Override
public void onPause() {
closeCamera();
stopBackgroundThread();
super.onPause();
}
public void setCamera(String cameraId) {
this.cameraId = cameraId;
}
/** Sets up member variables related to camera. */
private void setUpCameraOutputs() {
final Activity activity = getActivity();
final CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
final CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
final StreamConfigurationMap map =
characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
// Danger, W.R.! Attempting to use too large a preview size could exceed the camera
// bus' bandwidth limitation, resulting in gorgeous previews but the storage of
// garbage capture data.
previewSize =
chooseOptimalSize(
map.getOutputSizes(SurfaceTexture.class),
inputSize.getWidth(),
inputSize.getHeight());
// We fit the aspect ratio of TextureView to the size of preview we picked.
final int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
textureView.setAspectRatio(previewSize.getWidth(), previewSize.getHeight());
textureView.setVisibility(View.GONE);
} else {
textureView.setAspectRatio(previewSize.getHeight(), previewSize.getWidth());
textureView.setVisibility(View.GONE);
}
} catch (final CameraAccessException e) {
LOGGER.e(e, "Exception!");
} catch (final NullPointerException e) {
// Currently an NPE is thrown when the Camera2API is used but not supported on the
// device this code runs.
// TODO(andrewharp): abstract ErrorDialog/RuntimeException handling out into new method and
// reuse throughout app.
ErrorDialog.newInstance(getString(R.string.camera_error))
.show(getChildFragmentManager(), FRAGMENT_DIALOG);
throw new RuntimeException(getString(R.string.camera_error));
}
cameraConnectionCallback.onPreviewSizeChosen(previewSize, sensorOrientation);
}
/** Opens the camera specified by {#link CameraConnectionFragment#cameraId}. */
private void openCamera(final int width, final int height) {
setUpCameraOutputs();
configureTransform(width, height);
final Activity activity = getActivity();
final CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
manager.openCamera(cameraId, stateCallback, backgroundHandler);
} catch (final CameraAccessException e) {
LOGGER.e(e, "Exception!");
} catch (final InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
}
}
/** Closes the current {#link CameraDevice}. */
private void closeCamera() {
try {
cameraOpenCloseLock.acquire();
if (null != captureSession) {
captureSession.close();
captureSession = null;
}
if (null != cameraDevice) {
cameraDevice.close();
cameraDevice = null;
}
if (null != previewReader) {
previewReader.close();
previewReader = null;
}
} catch (final InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
} finally {
cameraOpenCloseLock.release();
}
}
/** Starts a background thread and its {#link Handler}. */
private void startBackgroundThread() {
backgroundThread = new HandlerThread("ImageListener");
backgroundThread.start();
backgroundHandler = new Handler(backgroundThread.getLooper());
}
/** Stops the background thread and its {#link Handler}. */
private void stopBackgroundThread() {
backgroundThread.quitSafely();
try {
backgroundThread.join();
backgroundThread = null;
backgroundHandler = null;
} catch (final InterruptedException e) {
LOGGER.e(e, "Exception!");
}
}
/** Creates a new {#link CameraCaptureSession} for camera preview. */
private void createCameraPreviewSession() {
try {
final SurfaceTexture texture = textureView.getSurfaceTexture();
assert texture != null;
// We configure the size of default buffer to be the size of camera preview we want.
texture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
// This is the output Surface we need to start preview.
final Surface surface = new Surface(texture);
// We set up a CaptureRequest.Builder with the output Surface.
previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
previewRequestBuilder.addTarget(surface);
LOGGER.i("Opening camera preview: " + previewSize.getWidth() + "x" + previewSize.getHeight());
// Create the reader for the preview frames.
previewReader =
ImageReader.newInstance(
previewSize.getWidth(), previewSize.getHeight(), ImageFormat.YUV_420_888, 2);
previewReader.setOnImageAvailableListener(imageListener, backgroundHandler);
previewRequestBuilder.addTarget(previewReader.getSurface());
// Here, we create a CameraCaptureSession for camera preview.
cameraDevice.createCaptureSession(
Arrays.asList(surface, previewReader.getSurface()),
new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(final CameraCaptureSession cameraCaptureSession) {
// The camera is already closed
if (null == cameraDevice) {
return;
}
// When the session is ready, we start displaying the preview.
captureSession = cameraCaptureSession;
try {
// Auto focus should be continuous for camera preview.
previewRequestBuilder.set(
CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// Flash is automatically enabled when necessary.
// previewRequestBuilder.set(
// CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
previewRequestBuilder.set(
CaptureRequest.FLASH_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
// Finally, we start displaying the camera preview.
previewRequest = previewRequestBuilder.build();
captureSession.setRepeatingRequest(
previewRequest, captureCallback, backgroundHandler);
} catch (final CameraAccessException e) {
LOGGER.e(e, "Exception!");
}
}
#Override
public void onConfigureFailed(final CameraCaptureSession cameraCaptureSession) {
showToast("Failed");
}
},
null);
} catch (final CameraAccessException e) {
LOGGER.e(e, "Exception!");
}
}
}
}
The second one:
public class LegacyCameraConnectionFragment extends Fragment {
private static final Logger LOGGER = new Logger();
/** Conversion from screen rotation to JPEG orientation. */
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
private Camera camera;
private Camera.PreviewCallback imageListener;
private Size desiredSize;
/** The layout identifier to inflate for this Fragment. */
private int layout;
/** An {#link AutoFitTextureView} for camera preview. */
private AutoFitTextureView textureView;
/**
* {#link TextureView.SurfaceTextureListener} handles several lifecycle events on a {#link
* TextureView}.
*/
private final TextureView.SurfaceTextureListener surfaceTextureListener =
new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(
final SurfaceTexture texture, final int width, final int height) {
int index = getCameraId();
camera = Camera.open(index);
try {
Camera.Parameters parameters = camera.getParameters();
List<String> focusModes = parameters.getSupportedFocusModes();
if (focusModes != null
&& focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
}
List<Camera.Size> cameraSizes = parameters.getSupportedPreviewSizes();
Size[] sizes = new Size[cameraSizes.size()];
int i = 0;
for (Camera.Size size : cameraSizes) {
sizes[i++] = new Size(size.width, size.height);
}
Size previewSize =
CameraConnectionFragment.chooseOptimalSize(
sizes, desiredSize.getWidth(), desiredSize.getHeight());
parameters.setPreviewSize(previewSize.getWidth(), previewSize.getHeight());
camera.setDisplayOrientation(90);
camera.setParameters(parameters);
camera.setPreviewTexture(texture);
} catch (IOException exception) {
camera.release();
}
camera.setPreviewCallbackWithBuffer(imageListener);
Camera.Size s = camera.getParameters().getPreviewSize();
camera.addCallbackBuffer(new byte[ImageUtils.getYUVByteSize(s.height, s.width)]);
textureView.setAspectRatio(s.height, s.width);
camera.startPreview();
}
#Override
public void onSurfaceTextureSizeChanged(
final SurfaceTexture texture, final int width, final int height) {}
#Override
public boolean onSurfaceTextureDestroyed(final SurfaceTexture texture) {
return true;
}
#Override
public void onSurfaceTextureUpdated(final SurfaceTexture texture) {}
};
/** An additional thread for running tasks that shouldn't block the UI. */
private HandlerThread backgroundThread;
#SuppressLint("ValidFragment")
public LegacyCameraConnectionFragment(
final Camera.PreviewCallback imageListener, final int layout, final Size desiredSize) {
this.imageListener = imageListener;
this.layout = layout;
this.desiredSize = desiredSize;
}
#Override
public View onCreateView(
final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return inflater.inflate(layout, container, false);
}
#Override
public void onViewCreated(final View view, final Bundle savedInstanceState) {
textureView = (AutoFitTextureView) view.findViewById(R.id.texture);
}
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onResume() {
super.onResume();
startBackgroundThread();
// When the screen is turned off and turned back on, the SurfaceTexture is already
// available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
// a camera and start preview from here (otherwise, we wait until the surface is ready in
// the SurfaceTextureListener).
if (textureView.isAvailable()) {
camera.startPreview();
} else {
textureView.setSurfaceTextureListener(surfaceTextureListener);
}
}
#Override
public void onPause() {
stopCamera();
stopBackgroundThread();
super.onPause();
}
/** Starts a background thread and its {#link Handler}. */
private void startBackgroundThread() {
backgroundThread = new HandlerThread("CameraBackground");
backgroundThread.start();
}
/** Stops the background thread and its {#link Handler}. */
private void stopBackgroundThread() {
backgroundThread.quitSafely();
try {
backgroundThread.join();
backgroundThread = null;
} catch (final InterruptedException e) {
LOGGER.e(e, "Exception!");
}
}
protected void stopCamera() {
if (camera != null) {
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
camera = null;
}
}
private int getCameraId() {
CameraInfo ci = new CameraInfo();
for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
Camera.getCameraInfo(i, ci);
if (ci.facing == CameraInfo.CAMERA_FACING_BACK) return i;
}
return -1; // No camera found
}
}
SOLUTION: in second block code:
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_ON);
mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,
CaptureRequest.FLASH_MODE_TORCH);
and in first block code:
//Check Whether device supports AutoFlash, If you YES then set AutoFlash
List<String> flashModes = parameters.getSupportedFlashModes();
if (flashModes.contains(android.hardware.Camera.Parameters.FLASH_MODE_AUTO))
{
parameters.setFlashMode(parameters.FLASH_MODE_AUTO);
}
SOLUTION: in second block code:
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_ON);
mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,
CaptureRequest.FLASH_MODE_TORCH);
and in first block code:
//Check Whether device supports AutoFlash, If you YES then set AutoFlash
List<String> flashModes = parameters.getSupportedFlashModes();
if (flashModes.contains(android.hardware.Camera.Parameters.FLASH_MODE_AUTO))
{
parameters.setFlashMode(parameters.FLASH_MODE_AUTO);
}

React Native Get battery status / level Using Native Modules

I am writing a react native app to get IOS and Android Battery status. I search through the net and found few libraries which can get battery level of the phone.
https://github.com/robinpowered/react-native-device-battery
https://github.com/remobile/react-native-battery-status
https://github.com/oojr/react-native-battery
Every library has issues when I try that and not much support for the developer when ask a question on git hub.
Can any one provide me better solution or library to get Battery status of IOS and Android.
Thanks in advance
I wrote my own IOS and Android classes to get the Battery Status. Here are the steps if any one interested on that,
For IOS,
Open the iOS project in XCode
Create 2 new files call BatteryStatus.h and BatteryStatus.m
BatteryStatus.h file should contain following code
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#interface BatteryStatus : RCTEventEmitter <RCTBridgeModule>
#end
BatteryStatus.m file should
#import "BatteryStatus.h"
#implementation BatteryStatus
RCT_EXPORT_MODULE(BatteryStatus)
- (instancetype)init
{
if ((self = [super init])) {
[[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
}
return self;
}
RCT_EXPORT_METHOD(hide) {
}
RCT_EXPORT_METHOD(updateBatteryLevel:(RCTResponseSenderBlock)callback)
{
callback(#[[self getBatteryStatus]]);
}
//manually get battery status by calling following method
-(NSDictionary*)getBatteryStatus
{
float batteryLevel = [UIDevice currentDevice].batteryLevel;
NSObject* currentLevel = nil;
currentLevel = [NSNumber numberWithFloat:(batteryLevel * 100)];
NSMutableDictionary* batteryData = [NSMutableDictionary dictionaryWithCapacity:2];
[batteryData setObject:currentLevel forKey:#"level"];
return batteryData;
}
#end
Inside your react native app, inside your js file add following code
import { NativeModules } from 'react-native';
constructor(props) {
super(props);
this.state = {
batteryLevel: null,
};
}
componentDidMount() {
NativeModules.BatteryStatus.updateBatteryLevel((info) => {
//console.log(info.level)
const level = Math.ceil(info.level);
this.setState({ batteryLevel: level});
});
}
For IOS above code is working for me to get the battery level
For Android,
Open the Android project in Android Studio
Create a group call BatteryStatus and include 2 Files named , BatteryStatusModule.java and BatteryStatusPackage.java
BatteryStatusModule.java Should contain following code
package com.yourproject.BatteryStatus;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class BatteryStatusModule extends ReactContextBaseJavaModule {
public BatteryStatusModule(ReactApplicationContext reactContext) {
super(reactContext);
}
#Override
public String getName() {
return "BatteryStatus";
}
#ReactMethod
public void getBatteryStatus(Callback successCallback) {
Intent batteryIntent = getCurrentActivity().registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
if(level == -1 || scale == -1) {
level = 0;
}
//System.out.print("battery level");
//System.out.print(level);
successCallback.invoke(null ,((float)level / (float)scale) * 100.0f);
}
}
BatteryStatusPackage.java should contain following code
package com.yourproject.BatteryStatus;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BatteryStatusPackage implements ReactPackage {
#Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new BatteryStatusModule(reactContext));
return modules;
}
#Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
#Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
Inside MainApplication.java include following code
#Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new MapsPackage(),
new BatteryStatusPackage()
);
}
Inside your react native app, inside your js file add following code
import { NativeModules } from 'react-native';
constructor(props) {
super(props);
this.state = {
batteryLevel: null
};
}
getBatteryLevel = (callback) => {
NativeModules.BatteryStatus.getBatteryStatus(callback);
}
6.Call it something like this:
componentDidMount() {
this.getBatteryLevel((batteryLevel) => {
console.log(batteryLevel);
});
}
For Android above code is working for me to get the battery level
Hope this will help some one to get battery level for IOS and ANDROID
We can use react-native-device-info for getting any device's specific information.
Install with command
npm install --save react-native-device-info
# or
yarn add react-native-device-info
Get the battery level of the device as a float comprised between 0 and 1 with getBatteryLevel().
DeviceInfo.getBatteryLevel().then(batteryLevel => {
console.log(batteryLevel);
// 0.759999
});
Note:
Returns -1 on the iOS Simulator
Just some addition to the right answer. You have to override the 'supportedEvents' function in the BatteryStatus.m file to make it work like this :
-(NSArray<NSString *> *)supportedEvents{
return #[#"level"];
}

Spigot Plugin - Cannot Build 1.10

I have created a Spigot plugin in 1.10. It is mostly essentials but I added in a compass inventory GUI and you receive it when you first log in. For some odd reason after I implemented this you cannot obtain items in your inventory, they instantly go away. The class for the GUI is below
package me.Roofah.Essentials;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.java.JavaPlugin;
public class Essentials extends JavaPlugin implements Listener{
public void onEnable() {
getServer().getPluginManager().registerEvents(this, this);
this.getCommand("teleport").setExecutor(new Teleport(this));;
this.getCommand("vanish").setExecutor(new Vanish(this));;
this.getCommand("unvanish").setExecutor(new Vanish(this));;
Bukkit.getServer().getLogger().info("Teleport Plugin Enabled!");
}
public Player getPlayer(String name) {
for(Player p : Bukkit.getOnlinePlayers()) {
if(p.getName().equalsIgnoreCase(name))
return p;
}
return null;
}
public void onDisable() {
Bukkit.getServer().getLogger().info("Teleport Plugin Disabled!");
}
private void teleportInWord(Player player, int x, int y, int z) {
player.teleport(new Location(player.getWorld(), x, y, z));
}
private void openGUI(Player player) {
Inventory inv = Bukkit.createInventory(null, 9, ChatColor.DARK_RED + "Warp Selector || By Roofah");
ItemStack Spawn = new ItemStack(Material.DIAMOND_AXE);
ItemMeta SpawnMeta = Spawn.getItemMeta();
ItemStack Build = new ItemStack(Material.DIAMOND_PICKAXE);
ItemMeta BuildMeta = Build.getItemMeta();
SpawnMeta.setDisplayName(ChatColor.DARK_RED + "Spawn");
Spawn.setItemMeta(SpawnMeta);
BuildMeta.setDisplayName(ChatColor.GREEN + "Build");
Build.setItemMeta(BuildMeta);
// 35
inv.setItem(3, Spawn);
inv.setItem(5, Build);
player.openInventory(inv);
}
#EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (ChatColor.stripColor(event.getInventory().getName()).equalsIgnoreCase("Warp Selector")) {
return;
}
Player player = (Player) event.getWhoClicked();
event.setCancelled(true);
if (event.getCurrentItem() == null || event.getCurrentItem().getType() == Material.AIR
|| !event.getCurrentItem().hasItemMeta()) {
player.closeInventory();
return;
}
switch(event.getCurrentItem().getType()){
case DIAMOND_AXE:
teleportInWord(player, 967, 90, 484);
player.closeInventory();
player.sendMessage(String.format("%sTeleported to %sSpawn%s!", ChatColor.GOLD, ChatColor.DARK_RED, ChatColor.GOLD));
break;
case DIAMOND_PICKAXE:
teleportInWord(player, 906, 96, 428);
player.closeInventory();
player.sendMessage(String.format("%sTeleported to %sBUILD%s!", ChatColor.GOLD, ChatColor.GREEN, ChatColor.GOLD));
break;
default:
player.closeInventory();
break;
}
}
#EventHandler
public void onPlayerKoin(PlayerJoinEvent event) {
event.getPlayer().getInventory().addItem(new ItemStack(Material.COMPASS));
}
#EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
Action a = event.getAction();
ItemStack is = event.getItem();
if (a == Action.PHYSICAL || is == null || is.getType() == Material.AIR) {
return;
}
if (is.getType() == Material.COMPASS) {
openGUI(event.getPlayer());
}
}
}
There are 2 other classes but I could still obtain blocks without adding in the GUI.
Your situation is a logic mistake at line 73 on your code.
You have the following:
if (ChatColor.stripColor(event.getInventory().getName()).equalsIgnoreCase("Warp Selector")) //Line 73 {
return;
}
The situation is:
Whenever the inventory name is Warp Selector, return. So your code is only executing when the inventory name is not "Warp Selector".
What you probably want is to invert this logic, so that your code will execute when the inventory name is "Warp Selector".
if (!ChatColor.stripColor(event.getInventory().getName()).equalsIgnoreCase("Warp Selector") {
return;
}
//Code continues

Is TextToSpeech supported on Google Glass?

I was wondering if TextToSpeech is supported on Google Glass?
I did something like this:
public class TextToSpeechController implements TextToSpeech.OnInitListener{
private Context mContext;
private TextToSpeech tts;
public TextToSpeechController(Context context) {
Log.e("TEXT TO SPEECH CONTROLLER", "controller");
mContext = context;
tts = new TextToSpeech(context, this);
}
#Override
public void onInit(int status) {
Log.e("INIT TTS", "INIT");
if (status == TextToSpeech.SUCCESS) {
int result = tts.setLanguage(Locale.ENGLISH);
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
Toast.makeText(mContext, "This Language is not supported", Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(mContext, "Ready to Speak", Toast.LENGTH_LONG).show();
speakTheText("Welcome to Vision Screening App");
}
}
else {
Toast.makeText(mContext, "Can Not Speak", Toast.LENGTH_LONG).show();
}
}
public void stopTTS(){
Log.e(".....TTS", "SHUTDOWN");
tts.stop();
tts.shutdown();
}
public void speakTheText(String str){
Log.e("SPEAK TEXT!!!!", "SPEAK TEXT");
tts.speak(str, TextToSpeech.QUEUE_FLUSH, null);
}
}
and in my Activity (onCreate) I have:
controller_tts = new TextToSpeechController(getApplicationContext());
I face several problems :
First of all the onInit method is not called at all, only at the moment when I exit the current Activity.
Somehow, after using TTS, the speeker's volume turns to mute and I cannot turn the volume back from the settings(only after I reboot the Glasses)
Am I doing something wrong? or simply Google Glass does not support TTS, even thought is hard to believe that.
Any suggestion is welcome! Thank you very much!:)
Is it possible that you are calling stopTTS before TextToSpeech is initialized?
This works just fine for me on Glass:
import android.app.Activity;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.view.MotionEvent;
import android.widget.TextView;
import java.util.Locale;
public class TTSTestActivity extends Activity
implements TextToSpeech.OnInitListener {
private TextToSpeech tts;
private boolean initialized = false;
private String queuedText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView view = new TextView(this);
view.setText("Tap Me");
setContentView(view);
tts = new TextToSpeech(this /* context */, this /* listener */);
}
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
initialized = true;
tts.setLanguage(Locale.ENGLISH);
if (queuedText != null) {
speak(queuedText);
}
}
}
public void speak(String text) {
// If not yet initialized, queue up the text.
if (!initialized) {
queuedText = text;
return;
}
queuedText = null;
// Before speaking the current text, stop any ongoing speech.
tts.stop();
// Speak the text.
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
}
#Override
public boolean onGenericMotionEvent(MotionEvent event) {
// On any motion event (including touchpad tap), say 'Hello Glass'
speak("Hello Glass");
return true;
}
}
With this example, anytime you tap the touch pad (or cause any other type of motion event), you should hear "Hello Glass." Note that if text is provided before TextToSpeech has initialized, then this is queued and then spoken after initialization is a success.
This does not include any tear-down, but to do that you can always put stop/shutdown of TextToSpeech in onDestroy() of the activity.

Auto connecting to a BLE device

I am working on an application to coommunicate against a BLE device, currently I am trying to create a Service that starts with the application and auto connect to TI's CC2541 keyfob.
Problem is the gatt server seem to fail EVERY TIME....
I have no clue whats wrong with my code since by google API's and some tutorials I saw
It seems that all the pieces are in their place, yet still nothing works... =(
Here is my service -
package com.example.bluetoothgatt;
import java.util.UUID;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
public class BLE extends Service implements BluetoothAdapter.LeScanCallback {
private final IBinder mBinder = new BluetoothLeBinder();
private final static String TAG = "BLE";
private static final String DEVICE_NAME = "Keyfobdemo";
private BluetoothManager mBluetoothManager;
public BluetoothGatt mConnectedGatt;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothDevice mDevice;
private String mDeviceAddress;
private int mConnectionState = STATE_DISCONNECTED;
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
/*******************************
*******************************
****** Service Inherited ****** Methods **********
*******************************/
#Override
public void onCreate() {
super.onCreate();
mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
Thread discoverDevices = new Thread(mStartRunnable);
discoverDevices.setPriority(discoverDevices.MAX_PRIORITY);
discoverDevices.start();
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
close();
return super.onUnbind(intent);
}
// Implements callback methods for GATT events that the app cares about.
// For example, connection change and services discovered.
private final BluetoothGattExecutor mExecutor = new BluetoothGattExecutor() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectionState = STATE_CONNECTED;
mConnectedGatt = gatt;
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
}
};
/**
* Return a reference for the current class
*/
public class BluetoothLeBinder extends Binder {
BLE getService() {
return BLE.this;
}
}
private Runnable mStartRunnable = new Runnable() {
#Override
public void run() {
startScan();
}
};
private void startScan() {
if (mConnectionState == STATE_DISCONNECTED) {
mBluetoothAdapter.startLeScan(this);
mHandler.postDelayed(mStopRunnable, 2500);
}
}
private Runnable mStopRunnable = new Runnable() {
#Override
public void run() {
stopScan();
}
};
private void stopScan() {
mBluetoothAdapter.stopLeScan(this);
}
#Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
/*
* We are looking for SensorTag devices only, so validate the name that
* each device reports before adding it to our collection
*/
if (DEVICE_NAME.equals(device.getName())) {
mDevice = device;
mDeviceAddress = mDevice.getAddress();
connect(mDeviceAddress);
mConnectionState = STATE_CONNECTING;
if(device.getBondState() == BluetoothDevice.BOND_BONDED) {
} else if (device.getBondState() == BluetoothDevice.BOND_BONDING) {
} else if(device.getBondState() == BluetoothDevice.BOND_NONE) {
connect(device.getAddress());
}
}
}
/**
* Connects to the GATT server hosted on the Bluetooth LE device.
*
* #param address
* The device address of the destination device.
*
* #return Return true if the connection is initiated successfully. The
* connection result is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG,
"BluetoothAdapter not initialized or unspecified address.");
return false;
}
// Previously connected device. Try to reconnect.
if (mDeviceAddress != null && address.equals(mDeviceAddress)
&& mConnectedGatt != null) {
Log.d(TAG,
"Trying to use an existing BluetoothGatt for connection.");
if (mConnectedGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter
.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the
// autoConnect
// parameter to false.
mConnectedGatt = device.connectGatt(this, false, mExecutor);
Log.d(TAG, "Trying to create a new connection.");
mDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
/**
* Disconnects an existing connection or cancel a pending connection. The
* disconnection result is reported asynchronously through the
* BluetoothGattCallback >>
* onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)
* callback.
*/
public void disconnect() {
if (mBluetoothAdapter == null || mConnectedGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mConnectedGatt.disconnect();
}
/**
* After using a given BLE device, the app must call this method to ensure
* resources are released properly.
*/
public void close() {
if (mConnectedGatt == null) {
return;
}
mConnectedGatt.close();
mConnectedGatt = null;
}
private final UUID IMMEDIATE_ALERT_UUID = UUID
.fromString("00001802-0000-1000-8000-00805f9b34fb");
private final UUID ALERT_LEVEL_UUID = UUID
.fromString("00002a06-0000-1000-8000-00805f9b34fb");
public void Buzz(BluetoothGatt gatt, int level) {
BluetoothGattService alertService = gatt
.getService(IMMEDIATE_ALERT_UUID);
if (alertService == null) {
Log.d(TAG, "Immediate Alert service not found!");
return;
}
BluetoothGattCharacteristic alertLevel = alertService
.getCharacteristic(ALERT_LEVEL_UUID);
if (alertLevel == null) {
Log.d(TAG, "Alert Level charateristic not found!");
return;
}
alertLevel.setValue(level, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
gatt.writeCharacteristic(alertLevel);
Log.d(TAG, "Alert");
}
private final UUID BATTERY_SERVICE_UUID = UUID
.fromString("0000180F-0000-1000-8000-00805f9b34fb");
private final UUID BATTERY_LEVEL_UUID = UUID
.fromString("00002a19-0000-1000-8000-00805f9b34fb");
public int getbattery(BluetoothGatt mBluetoothGatt) {
BluetoothGattService batteryService = mConnectedGatt
.getService(BATTERY_SERVICE_UUID);
if (batteryService == null) {
Log.d(TAG, "Battery service not found!");
return 0;
}
BluetoothGattCharacteristic batteryLevel = batteryService
.getCharacteristic(BATTERY_LEVEL_UUID);
if (batteryLevel == null) {
Log.d(TAG, "Battery level not found!");
return 0;
}
mBluetoothGatt.readCharacteristic(batteryLevel);
return batteryLevel.getIntValue(
BluetoothGattCharacteristic.FORMAT_SINT8, 0);
}
/*
* We have a Handler to process event results on the main thread
*/
private static final int MSG_PROGRESS = 201;
private static final int MSG_DISMISS = 202;
private static final int MSG_CLEAR = 301;
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
BluetoothGattCharacteristic characteristic;
switch (msg.what) {
case MSG_PROGRESS:
break;
case MSG_DISMISS:
break;
case MSG_CLEAR:
break;
}
}
};
public void MakeBuzz() {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
mConnectedGatt = mDevice.connectGatt(getApplicationContext(),
true, mExecutor);
BluetoothGattService alertService = mConnectedGatt
.getService(IMMEDIATE_ALERT_UUID);
int x = getbattery(mConnectedGatt);
Buzz(mConnectedGatt, 2);
}
});
t.start();
}
}
This it the Application class -
package com.example.bluetoothgatt;
import android.app.Application;
import android.content.Intent;
public class ApplicationBleTest extends Application {
// Application variables
public final String SMOKE_TALK_PACKAGE_NAME = "com.smoketalk";
private BluetoothLEService mBleService;
private static int MODE_PRIVATE;
/**
* Application OnCreate event initiate the class parameters
*/
public void onCreate() {
super.onCreate();
getApplicationContext().startService(new Intent(this, BLE.class));
}
}
And this is the main activity (I am trying to make the keyfob alaram buzz on a button click)
package com.example.bluetoothgatt;
import com.example.bluetoothgatt.BluetoothLowEnergyService.BluetoothLeBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
/**
* Created by Dave Smith Double Encore, Inc. MainActivity
*/
public class MainActivity extends Activity {
BluetoothLowEnergyService mBluetoothService;
boolean isBound = false;
Button buzz;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, BluetoothLowEnergyService.class);
bindService(intent, mBleServiceConnection, Context.BIND_AUTO_CREATE);
buzz = (Button) findViewById(R.id.btn1);
buzz.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mBluetoothService.MakeBuzz();
}
});
}
private ServiceConnection mBleServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
BluetoothLeBinder binder = (BluetoothLeBinder) service;
mBluetoothService = binder.getService();
isBound = true;
}
public void onServiceDisconnected(ComponentName arg0) {
isBound = false;
}
};
}
And the menifest file -
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.bluetoothgatt"
android:versionCode="1"
android:versionName="1.0" >
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
<uses-sdk
android:minSdkVersion="18"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED"/>
<application
android:name="com.example.bluetoothgatt.ApplicationBleTest"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="SensorTag Weather" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.example.bluetoothgatt.BLE" />
</application>
</manifest>
and last one the layout for the main activity -
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:padding="#dimen/activity_horizontal_margin"
android:text="Android BLE Test"
android:textSize="42sp" />
<Button
android:id="#+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView1"
android:layout_centerHorizontal="true"
android:layout_marginTop="56dp"
android:text="Buzz" />
</RelativeLayout>
ANY help will be appreciated since I rellay have no clue what goes wrong... =(
For starters, I would recommend commenting out the bond code (Everything after if(device.getBondState().. in the onLeScan method) The whole bonding process was unstable on 4.3 (Nexus devices at least) and became more stable on 4.4.
You should be able to discover devices, and with the BluetoothDevice the user selects you should call ConnectGatt after stopping discovery. This will attempt to connect to the Gatt server on the device. If the connection is successful, you should receive a callback on your connectionStateChange indicating that the connection was successful.
The concept behind bonding is related to pairing with the device and exchanging keys if your characteristics are encrypted. Normally you should be able to connect to the Gatt server without needing to bond, but once you are connected, if you do try to read an encrypted characteristic, it will fail.
I tried your code and it works. you need to follow this process:
BluetoothAdapter.startLeScan(leCallback)
In the onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) in leCallback, call btDevice.connectGatt(Context context, Boolean autoConnect, BluetoothGattCallback gattCallback);
In the onConnectionStateChange(BluetoothGatt gatt, int status, int newState) in gattCallBack, check if newState is BluetoothProfile.STATE_CONNECTED, if yes, call gatt.discoverServices();
In the onServicesDiscovered(BluetoothGatt gatt, int status) in gattCallBack, check if status is BluetoothGatt.GATT_SUCCESS, if yes, get the service by UUID like this: BluetoothGattService service = gatt.getService(YOUR_SERVICE_UUID);
If the service is null, it means the service has not yet been discovered, you need to check again when the next service is discovered and the onServicesDiscovered will be called again.
By the time all the services has been discovered, you should already got your service, unless the device does not support it.
Now you can use your service in your Buzz method.
Also worth noting is that the BLE actions must all be serialized by you. Eg, if you made a read/write to a characteristic you need to wait for the callback before doing another. If not, this will result in an error.
Since you are running from a service you can try running connect on the main thread like this:
public void connectToDevice( String deviceAddress) {
mDeviceAddress = deviceAddress;
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(mDeviceAddress);
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
if (device != null) {
mGatt = device.connectGatt(getApplicationContext(), true, mGattCallback);
scanLeDevice(false);// will stop after first device detection
}
}
});
}
Hope it helps.