Hey guys I have a problem with Google mobile vision API and especially with data-matrix format .
I'm able to scan almost every Barcode format but when I want to scan data-matrix, things getting harder . I can only detect one in 10, it's very embarrasing.
I followed the doc and I added followed detection formats like follow :
1D barcodes: EAN-13, EAN-8, UPC-A, UPC-E, Code-39, Code-93, Code-128, ITF, Codabar
2D barcodes: QR Code, Data Matrix, PDF-417, AZTEC
My Activity looks like this (took on : Google vision Android Github)
public class QrScanActivity extends AppCompatActivity implements BarcodeTracker.BarcodeTrackerListener {
private static final String TAG = QrScanActivity.class.getSimpleName();
// permission request codes need to be < 256
private static final int RC_HANDLE_CAMERA_PERM = 2;
public static final String BARCODE_OBJECT = "Barcode";
private CameraSource _cameraSource;
private CameraSourcePreview _preview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qrscan);
_preview = this.findViewById(R.id.preview);
// Check for the camera permission before accessing the camera. If the
// permission is not granted yet, request permission.
int rc = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
if (rc == PackageManager.PERMISSION_GRANTED) {
createCameraSource(true);
} else {
requestCameraPermission();
}
}
/**
* Handles the requesting of the camera permission. This includes
* showing a "Snackbar" message of why the permission is needed then
* sending the request.
*/
private void requestCameraPermission() {
Log.w(TAG, "Camera permission is not granted. Requesting permission");
final String[] permissions = new String[]{Manifest.permission.CAMERA};
if (!ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.CAMERA)) {
ActivityCompat.requestPermissions(this, permissions, RC_HANDLE_CAMERA_PERM);
return;
}
View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View view) {
ActivityCompat.requestPermissions(QrScanActivity.this, permissions,
RC_HANDLE_CAMERA_PERM);
}
};
}
/**
* Creates and starts the camera. Note that this uses a higher resolution in comparison
* to other detection examples to enable the barcode detector to detect small barcodes
* at long distances.
* <p>
* Suppressing InlinedApi since there is a check that the minimum version is met before using
* the constant.
*/
#SuppressLint("InlinedApi")
private void createCameraSource(boolean autoFocus) {
Context context = getApplicationContext();
// A barcode detector is created to track barcodes. An associated multi-processor instance
// is set to receive the barcode detection results, track the barcodes, and maintain
// graphics for each barcode on screen. The factory is used by the multi-processor to
// create a separate tracker instance for each barcode.
BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).setBarcodeFormats(Barcode.QR_CODE | Barcode.DATA_MATRIX | Barcode.AZTEC | Barcode.PDF417 | Barcode.CODE_39 |
Barcode.EAN_8 | Barcode.EAN_13 | Barcode.UPC_A | Barcode.UPC_E | Barcode.CODE_93 | Barcode.CODE_128 | Barcode.ITF | Barcode.CODABAR).build();
BarcodeTracker tracker = new BarcodeTracker(this);
barcodeDetector.setProcessor(
new FirstItemProcessor(barcodeDetector, tracker));
if (!barcodeDetector.isOperational()) {
// Note: The first time that an app using the barcode or face API is installed on a
// device, GMS will download a native libraries to the device in order to do detection.
// Usually this completes before the app is run for the first time. But if that
// download has not yet completed, then the above call will not detect any barcodes
// and/or faces.
//
// isOperational() can be used to check if the required native libraries are currently
// available. The detectors will automatically become operational once the library
// downloads complete on device.
Log.w(TAG, "Detector dependencies are not yet available.");
// Check for low storage. If there is low storage, the native library will not be
// downloaded, so detection will not become operational.
IntentFilter lowstorageFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
boolean hasLowStorage = registerReceiver(null, lowstorageFilter) != null;
if (hasLowStorage) {
Toast.makeText(this, "low storage", Toast.LENGTH_LONG).show();
Log.w(TAG, "low storage error");
}
}
// Creates and starts the camera. Note that this uses a higher resolution in comparison
// to other detection examples to enable the barcode detector to detect small barcodes
// at long distances.
CameraSource.Builder builder = new CameraSource.Builder(getApplicationContext(), barcodeDetector)
.setFacing(CameraSource.CAMERA_FACING_BACK)
//.setRequestedPreviewSize(getWindow().getDecorView().getHeight(), getWindow().getDecorView().getWidth())
.setRequestedFps(30.0f);
builder = builder.setAutoFocusEnabled(autoFocus);
_cameraSource = builder.build();
}
/**
* Restarts the camera.
*/
#Override
protected void onResume() {
super.onResume();
startCameraSource();
((TracksApplication) getApplication()).set_currentClass(getClass().getSimpleName());
}
/**
* Stops the camera.
*/
#Override
protected void onPause() {
super.onPause();
if (_preview != null) {
_preview.stop();
}
}
/**
* Releases the resources associated with the camera source, the associated detectors, and the
* rest of the processing pipeline.
*/
#Override
protected void onDestroy() {
super.onDestroy();
if (_preview != null) {
_preview.release();
}
}
/**
* Callback for the result from requesting permissions. This method
* is invoked for every call on {#link #requestPermissions(String[], int)}.
* <p>
* <strong>Note:</strong> It is possible that the permissions request interaction
* with the user is interrupted. In this case you will receive empty permissions
* and results arrays which should be treated as a cancellation.
* </p>
*
* #param requestCode The request code passed in {#link #requestPermissions(String[], int)}.
* #param permissions The requested permissions. Never null.
* #param grantResults The grant results for the corresponding permissions
* which is either {#link PackageManager#PERMISSION_GRANTED}
* or {#link PackageManager#PERMISSION_DENIED}. Never null.
* #see #requestPermissions(String[], int)
*/
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String[] permissions,
#NonNull int[] grantResults) {
if (requestCode != RC_HANDLE_CAMERA_PERM) {
Log.d(TAG, "Got unexpected permission result: " + requestCode);
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
return;
}
if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Camera permission granted - initialize the camera source");
// we have permission, so create the camerasourc
createCameraSource(true);
return;
}
Log.e(TAG, "Permission not granted: results len = " + grantResults.length +
" Result code = " + (grantResults.length > 0 ? grantResults[0] : "(empty)"));
}
/**
* Starts or restarts the camera source, if it exists. If the camera source doesn't exist yet
* (e.g., because onResume was called before the camera source was created), this will be called
* again when the camera source is created.
*/
private void startCameraSource() throws SecurityException {
if (_cameraSource != null) {
try {
_preview.start(_cameraSource);
} catch (IOException e) {
Log.e(TAG, "Unable to start camera source.", e);
_cameraSource.release();
_cameraSource = null;
}
}
}
#Override
public void onBarcodeDetected(Barcode barcode) {
Intent data = new Intent();
data.putExtra(BARCODE_OBJECT, barcode);
setResult(CommonStatusCodes.SUCCESS, data);
finish();
}
}
I don't know what is wrong, if someone have an idea...
The problem is "solved" , it appears to be a problem with datamatrix that I received.
Because I tried to scan those with multiple scanner like an IOS device , or a Google play store application , everything and they are not recognized too.
Related
I build an app where the user has an FAB to start some hidden image recording with camera2 API and some other location stuff - now the user has the option to open a preview with an item from navigation drawer. The problem is that if I start hidden recording over FAB and then click to open the preview, the statecallback onDisconnected from CameraDevice is called and the hidden recording is disabled due to CameraDevice with ID 0 is no longer available.
My code is like the sample Camera2Video from Google:
https://github.com/googlesamples/android-Camera2Video
private CameraDevice mCameraDevice;
private CaptureRequest.Builder mPreviewBuilder;
private CameraCaptureSession mPreviewSession;
/**
* A {#link Semaphore} to prevent the app from exiting before closing the camera.
*/
private Semaphore mCameraOpenCloseLock = new Semaphore(1);
/**
* {#link CameraDevice.StateCallback} is called when {#link CameraDevice} changes its status.
*/
private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(#NonNull CameraDevice cameraDevice) {
mCameraDevice = cameraDevice;
Log.d(TAG, "onOpened: ");
File dir = new File(mNextVideoDirPath);
if(dir.mkdirs()) {
startRecordingVideo();
}
else {
Toast.makeText(context,
"Error: Could not start recording. Directory for saved files could not be created", Toast.LENGTH_SHORT).show();
}
mCameraOpenCloseLock.release();
}
#Override
public void onDisconnected(#NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
}
#Override
public void onError(#NonNull CameraDevice cameraDevice, int error) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
}
};
If I do at first the preview and then start the hidden recording the preview freezes and hidden recording starts.
I have an Huawei P30 pro and tried to just change the ID of camera device but instead of front camera it's crashing.
So is there a differnt approach for some use case like this or isn't it even possible to do so OR how can I prevent some disconnection?
UPDATE
I found an article about multiple streams from on e device on medium from android developers
https://medium.com/androiddevelopers/using-multiple-camera-streams-simultaneously-bf9488a29482
Maybe I can add those targets before I do the stuff..
Something like this:
https://gist.github.com/owahltinez/f615e13bfc3497a0bd5d1427eae6c54f#file-using-multiple-camera-streams-01-kt
UPDATE END
If necessary I can provide some more code, but it's most like the sample from google.
Thank you for your time!
I'm on a project to create an app on Android studio, to fetch data from a Google spreadsheet to work with it.
So I tried to work on it by trying the spreadsheet-quickstart for Android (Apiv4), on the Google documentation.
So I launch the quickstart app on my device.
But I've every time is displayed an error, when I launch my app on my device, especially when the program call the google sheet, and I can't connect to the sheet:
The following error occurred: null
I take a look on the program, retrieved where is that error to debug which is on the method onCancelled(). But I don't really understand some parts of the program is used, for example this method with "..." which seems have an important role to debug my error:
protected List<String> doInBackground(Void... params)
I followed perfectly the tutorial, working on Android Studio, started over 3 times, but always the same issue. I'm not confident at all with Java, and Android (first real app). That's why I need your help, to learn what I'm doing wrong.
I resume below the steps I followed, and the program I've done:
Retrieve my Sha1 FingerPrint on my computer (cmd.exe command)
Create my google spreadsheet
Activation of my Api for Android, and put my SHA1 fingerprint and the package I'll use for my app
Create my app as the tutorial said
Change the build.gradle (the good one) and Sync it
Change the AndroidManifest.xml:
Create my MainActivity.java, and replace with this code.
Build an apk, and transfer this one on my OnePlus3 (my Android phone) via USB.
Install this apk, and launch it.
Click on this button, log with my google account, display Calling Google Sheet Api, then stop it and display this error:
The following error occurred: null
Build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
applicationId "com.example.quickstart"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
} }
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.google.android.gms:play-services:8.1.0'
testCompile 'junit:junit:4.12'
compile 'pub.devrel:easypermissions:0.2.1'
compile('com.google.api-client:google-api-client-android:1.22.0') {
exclude group: 'org.apache.httpcomponents'
}
compile('com.google.apis:google-api-services-sheets:v4-rev476-1.22.0') {
exclude group: 'org.apache.httpcomponents'
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.quickstart">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="Google Sheets API Android Quickstart"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="Google Sheets API Android Quickstart" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity.java:
package com.example.quickstart;
import android.Manifest;
import android.accounts.AccountManager;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.googleapis.extensions.android.gms.auth.GooglePlayServicesAvailabilityIOException;
import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.ExponentialBackOff;
import com.google.api.services.sheets.v4.SheetsScopes;
import com.google.api.services.sheets.v4.model.ValueRange;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import pub.devrel.easypermissions.AfterPermissionGranted;
import pub.devrel.easypermissions.EasyPermissions;
public class MainActivity extends Activity
implements EasyPermissions.PermissionCallbacks {
GoogleAccountCredential mCredential;
private TextView mOutputText;
private Button mCallApiButton;
ProgressDialog mProgress;
static final int REQUEST_ACCOUNT_PICKER = 1000;
static final int REQUEST_AUTHORIZATION = 1001;
static final int REQUEST_GOOGLE_PLAY_SERVICES = 1002;
static final int REQUEST_PERMISSION_GET_ACCOUNTS = 1003;
private static final String BUTTON_TEXT = "Call Google Sheets API";
private static final String PREF_ACCOUNT_NAME = "accountName";
private static final String[] SCOPES = { SheetsScopes.SPREADSHEETS_READONLY };
/**
* Create the main activity.
* #param savedInstanceState previously saved instance data.
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout activityLayout = new LinearLayout(this);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
activityLayout.setLayoutParams(lp);
activityLayout.setOrientation(LinearLayout.VERTICAL);
activityLayout.setPadding(16, 16, 16, 16);
ViewGroup.LayoutParams tlp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
mCallApiButton = new Button(this);
mCallApiButton.setText(BUTTON_TEXT);
mCallApiButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCallApiButton.setEnabled(false);
mOutputText.setText("");
getResultsFromApi();
mCallApiButton.setEnabled(true);
}
});
activityLayout.addView(mCallApiButton);
mOutputText = new TextView(this);
mOutputText.setLayoutParams(tlp);
mOutputText.setPadding(16, 16, 16, 16);
mOutputText.setVerticalScrollBarEnabled(true);
mOutputText.setMovementMethod(new ScrollingMovementMethod());
mOutputText.setText(
"Click the \'" + BUTTON_TEXT +"\' button to test the API.");
activityLayout.addView(mOutputText);
mProgress = new ProgressDialog(this);
mProgress.setMessage("Calling Google Sheets API ...");
setContentView(activityLayout);
// Initialize credentials and service object.
mCredential = GoogleAccountCredential.usingOAuth2(
getApplicationContext(), Arrays.asList(SCOPES))
.setBackOff(new ExponentialBackOff());
}
/**
* Attempt to call the API, after verifying that all the preconditions are
* satisfied. The preconditions are: Google Play Services installed, an
* account was selected and the device currently has online access. If any
* of the preconditions are not satisfied, the app will prompt the user as
* appropriate.
*/
private void getResultsFromApi() {
if (! isGooglePlayServicesAvailable()) {
acquireGooglePlayServices();
} else if (mCredential.getSelectedAccountName() == null) {
chooseAccount();
} else if (! isDeviceOnline()) {
mOutputText.setText("No network connection available.");
} else {
new MakeRequestTask(mCredential).execute();
}
}
/**
* Attempts to set the account used with the API credentials. If an account
* name was previously saved it will use that one; otherwise an account
* picker dialog will be shown to the user. Note that the setting the
* account to use with the credentials object requires the app to have the
* GET_ACCOUNTS permission, which is requested here if it is not already
* present. The AfterPermissionGranted annotation indicates that this
* function will be rerun automatically whenever the GET_ACCOUNTS permission
* is granted.
*/
#AfterPermissionGranted(REQUEST_PERMISSION_GET_ACCOUNTS)
private void chooseAccount() {
if (EasyPermissions.hasPermissions(
this, Manifest.permission.GET_ACCOUNTS)) {
String accountName = getPreferences(Context.MODE_PRIVATE)
.getString(PREF_ACCOUNT_NAME, null);
if (accountName != null) {
mCredential.setSelectedAccountName(accountName);
getResultsFromApi();
} else {
// Start a dialog from which the user can choose an account
startActivityForResult(
mCredential.newChooseAccountIntent(),
REQUEST_ACCOUNT_PICKER);
}
} else {
// Request the GET_ACCOUNTS permission via a user dialog
EasyPermissions.requestPermissions(
this,
"This app needs to access your Google account (via Contacts).",
REQUEST_PERMISSION_GET_ACCOUNTS,
Manifest.permission.GET_ACCOUNTS);
}
}
/**
* Called when an activity launched here (specifically, AccountPicker
* and authorization) exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
* #param requestCode code indicating which activity result is incoming.
* #param resultCode code indicating the result of the incoming
* activity result.
* #param data Intent (containing result data) returned by incoming
* activity result.
*/
#Override
protected void onActivityResult(
int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case REQUEST_GOOGLE_PLAY_SERVICES:
if (resultCode != RESULT_OK) {
mOutputText.setText(
"This app requires Google Play Services. Please install " +
"Google Play Services on your device and relaunch this app.");
} else {
getResultsFromApi();
}
break;
case REQUEST_ACCOUNT_PICKER:
if (resultCode == RESULT_OK && data != null &&
data.getExtras() != null) {
String accountName =
data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
if (accountName != null) {
SharedPreferences settings =
getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
editor.putString(PREF_ACCOUNT_NAME, accountName);
editor.apply();
mCredential.setSelectedAccountName(accountName);
getResultsFromApi();
}
}
break;
case REQUEST_AUTHORIZATION:
if (resultCode == RESULT_OK) {
getResultsFromApi();
}
break;
}
}
/**
* Respond to requests for permissions at runtime for API 23 and above.
* #param requestCode The request code passed in
* requestPermissions(android.app.Activity, String, int, String[])
* #param permissions The requested permissions. Never null.
* #param grantResults The grant results for the corresponding permissions
* which is either PERMISSION_GRANTED or PERMISSION_DENIED. Never null.
*/
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String[] permissions,
#NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(
requestCode, permissions, grantResults, this);
}
/**
* Callback for when a permission is granted using the EasyPermissions
* library.
* #param requestCode The request code associated with the requested
* permission
* #param list The requested permission list. Never null.
*/
#Override
public void onPermissionsGranted(int requestCode, List<String> list) {
// Do nothing.
}
/**
* Callback for when a permission is denied using the EasyPermissions
* library.
* #param requestCode The request code associated with the requested
* permission
* #param list The requested permission list. Never null.
*/
#Override
public void onPermissionsDenied(int requestCode, List<String> list) {
// Do nothing.
}
/**
* Checks whether the device currently has a network connection.
* #return true if the device has a network connection, false otherwise.
*/
private boolean isDeviceOnline() {
ConnectivityManager connMgr =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
return (networkInfo != null && networkInfo.isConnected());
}
/**
* Check that Google Play services APK is installed and up to date.
* #return true if Google Play Services is available and up to
* date on this device; false otherwise.
*/
private boolean isGooglePlayServicesAvailable() {
GoogleApiAvailability apiAvailability =
GoogleApiAvailability.getInstance();
final int connectionStatusCode =
apiAvailability.isGooglePlayServicesAvailable(this);
return connectionStatusCode == ConnectionResult.SUCCESS;
}
/**
* Attempt to resolve a missing, out-of-date, invalid or disabled Google
* Play Services installation via a user dialog, if possible.
*/
private void acquireGooglePlayServices() {
GoogleApiAvailability apiAvailability =
GoogleApiAvailability.getInstance();
final int connectionStatusCode =
apiAvailability.isGooglePlayServicesAvailable(this);
if (apiAvailability.isUserResolvableError(connectionStatusCode)) {
showGooglePlayServicesAvailabilityErrorDialog(connectionStatusCode);
}
}
/**
* Display an error dialog showing that Google Play Services is missing
* or out of date.
* #param connectionStatusCode code describing the presence (or lack of)
* Google Play Services on this device.
*/
void showGooglePlayServicesAvailabilityErrorDialog(
final int connectionStatusCode) {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
Dialog dialog = apiAvailability.getErrorDialog(
MainActivity.this,
connectionStatusCode,
REQUEST_GOOGLE_PLAY_SERVICES);
dialog.show();
}
/**
* An asynchronous task that handles the Google Sheets API call.
* Placing the API calls in their own task ensures the UI stays responsive.
*/
private class MakeRequestTask extends AsyncTask<Void, Void, List<String>> {
private com.google.api.services.sheets.v4.Sheets mService = null;
private Exception mLastError = null;
MakeRequestTask(GoogleAccountCredential credential) {
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
mService = new com.google.api.services.sheets.v4.Sheets.Builder(
transport, jsonFactory, credential)
.setApplicationName("Google Sheets API Android Quickstart")
.build();
}
/**
* Background task to call Google Sheets API.
* #param params no parameters needed for this task.
*/
#Override
protected List<String> doInBackground(Void... params) {
try {
return getDataFromApi();
} catch (Exception e) {
mLastError = e;
cancel(true);
return null;
}
}
/**
* Fetch a list of names and majors of students in a sample spreadsheet:
* https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
* #return List of names and majors
* #throws IOException
*/
private List<String> getDataFromApi() throws IOException {
String spreadsheetId = "629235369054-3cc387mt7mlnacv1kiq8d30auhqrh278.apps.googleusercontent.com";
String range = "GroupMar!A2:C";
List<String> results = new ArrayList<String>();
ValueRange response = this.mService.spreadsheets().values()
.get(spreadsheetId, range)
.execute();
List<List<Object>> values = response.getValues();
if (values != null) {
results.add("Name, Major");
for (List row : values) {
results.add(row.get(0) + ", " + row.get(1) + ", " + row.get(2));
}
}
return results;
}
#Override
protected void onPreExecute() {
mOutputText.setText("");
mProgress.show();
}
#Override
protected void onPostExecute(List<String> output) {
mProgress.hide();
if (output == null || output.size() == 0) {
mOutputText.setText("No results returned.");
} else {
output.add(0, "Data retrieved using the Google Sheets API:");
mOutputText.setText(TextUtils.join("\n", output));
}
}
#Override
protected void onCancelled() {
mProgress.hide();
if (mLastError != null) {
if (mLastError instanceof GooglePlayServicesAvailabilityIOException) {
showGooglePlayServicesAvailabilityErrorDialog(
((GooglePlayServicesAvailabilityIOException) mLastError)
.getConnectionStatusCode());
} else if (mLastError instanceof UserRecoverableAuthIOException) {
startActivityForResult(
((UserRecoverableAuthIOException) mLastError).getIntent(),
MainActivity.REQUEST_AUTHORIZATION);
} else {
mOutputText.setText("The following error occurred:\n"
+ mLastError.getMessage());
}
} else {
mOutputText.setText("Request cancelled.");
}
}
}
}
Can anyone help me to understand?
UPDATE: Easier way to get the SHA1 key (compared to the link i've posted in my answer) - https://stackoverflow.com/a/34223470/7368208 - If it doesn't work, the answer linked below will definitely work
I had the same problem. This error occurs when the app is unable to sign-in i.e. invalid credentials. So the problem could be
Credentials not created (but you mentioned you did) so..
Credentials mismatch between app and developers console e.g. wrong SHA1 key
The issue I faced was that the SHA1 key obtained via keytool didnt match with the actual key used in the app. So first get the SHA1 key thats actually used in the app. Check this post to see how to get the SHA1 key used in the app. If its different from the keytool key then updating it in the developers console will solve your problem.
I'm developing a music player application. In which, I want to display a small floating button on screen for play/pause event when app is minimized(paused). (Functionality like face book messenger chat head). It works perfectly fine on devices which has SDK < 23. But in Device with SDK >= 23, It asks for permission only 1st time when app in installed.
If permission is granted, it also perfectly displays floating button. But once the app is closed and again started, It is not showing floating button any more.
my code for opening permission dialogue box is:
public final static int REQUEST_CODE = 100;
public void checkDrawOverlayPermission() {
/** check if we already have permission to draw over other apps */
if (!Settings.canDrawOverlays(this)) {
/** if not construct intent to request permission */
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
/** request permission via start activity for result */
startActivityForResult(intent, REQUEST_CODE);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
/** check if received result code
is equal our requested code for draw permission */
if (requestCode == REQUEST_CODE) {
if (Settings.canDrawOverlays(this)) {
// continue here - permission was granted
if(isServiceRunning != true){
isServiceRunning = true;
intent12 = new Intent(this, notificationService.class);
bindService(intent12, notificationConnection, Context.BIND_AUTO_CREATE);
startService(intent12);
}
}
}
}
I'm displaying floating button when app is paused(when home button or back button is pressed to minimize the app). So I'm calling this checkDrawOverlayPermission() method in onPause() method of my apps mainActivity, like this:
#Override
protected void onPause() {
super.onPause();
if (Build.VERSION.SDK_INT >= 23) {
checkDrawOverlayPermission();
} else {
if(isServiceRunning != true){
isServiceRunning = true;
intent12 = new Intent(this, notificationService.class);
bindService(intent12, notificationConnection, Context.BIND_AUTO_CREATE);
startService(intent12);
}
}
}
But I can't understand what I'm missing here. I think code for checking permission is ok because first time it displays floating button on the screen along with asking permission in a small dialogue. Please help. Thanks!
You are not doing anything if the permission is already given in SDK > 23.
Add an else part to the checkDrawOverlayPermission method like this.
public void checkDrawOverlayPermission() {
/** check if we already have permission to draw over other apps */
if (!Settings.canDrawOverlays(this)) { // WHAT IF THIS EVALUATES TO FALSE.
/** if not construct intent to request permission */
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
/** request permission via start activity for result */
startActivityForResult(intent, REQUEST_CODE);
} else { // ADD THIS.
// Add code to bind and start the service directly.
}
}
I am using Barcode Scanner in my app. In some mobile it is giving the run-time exception Fail to connect to camera.
Here is the code I am using for Camera
/**
* Opens the camera and applies the user settings.
*
* #throws RuntimeException if the method fails
*/
#SuppressLint("InlinedApi")
private Camera createCamera() {
int requestedCameraId = getIdForRequestedCamera(mFacing);
if (requestedCameraId == -1) {
throw new RuntimeException("Could not find requested camera.");
}
Camera camera = Camera.open(requestedCameraId);
SizePair sizePair = selectSizePair(camera, mRequestedPreviewWidth, mRequestedPreviewHeight);
if (sizePair == null) {
throw new RuntimeException("Could not find suitable preview size.");
}
Size pictureSize = sizePair.pictureSize();
mPreviewSize = sizePair.previewSize();
int[] previewFpsRange = selectPreviewFpsRange(camera, mRequestedFps);
if (previewFpsRange == null) {
throw new RuntimeException("Could not find suitable preview frames per second range.");
}
Camera.Parameters parameters = camera.getParameters();
if (pictureSize != null) {
parameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());
}
parameters.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
parameters.setPreviewFpsRange(
previewFpsRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
previewFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
parameters.setPreviewFormat(ImageFormat.NV21);
setRotation(camera, parameters, requestedCameraId);
if (mFocusMode != null) {
if (parameters.getSupportedFocusModes().contains(
mFocusMode)) {
parameters.setFocusMode(mFocusMode);
} else {
Log.i(TAG, "Camera focus mode: " + mFocusMode + " is not supported on this device.");
}
}
// setting mFocusMode to the one set in the params
mFocusMode = parameters.getFocusMode();
if (mFlashMode != null) {
if (parameters.getSupportedFlashModes() != null) {
if (parameters.getSupportedFlashModes().contains(
mFlashMode)) {
parameters.setFlashMode(mFlashMode);
} else {
Log.i(TAG, "Camera flash mode: " + mFlashMode + " is not supported on this device.");
}
}
}
// setting mFlashMode to the one set in the params
mFlashMode = parameters.getFlashMode();
camera.setParameters(parameters);
// Four frame buffers are needed for working with the camera:
//
// one for the frame that is currently being executed upon in doing detection
// one for the next pending frame to process immediately upon completing detection
// two for the frames that the camera uses to populate future preview images
camera.setPreviewCallbackWithBuffer(new CameraPreviewCallback());
camera.addCallbackBuffer(createPreviewBuffer(mPreviewSize));
camera.addCallbackBuffer(createPreviewBuffer(mPreviewSize));
camera.addCallbackBuffer(createPreviewBuffer(mPreviewSize));
camera.addCallbackBuffer(createPreviewBuffer(mPreviewSize));
return camera;
}
* Stops the camera.
*/
#Override
protected void onPause() {
super.onPause();
if (mPreview != null) {
mPreview.stop();
}
}
/**
* Releases the resources associated with the camera source, the associated detectors, and the
* rest of the processing pipeline.
*/
#Override
protected void onDestroy() {
super.onDestroy();
if (mPreview != null) {
mPreview.release();
}
}
/**
* Restarts the camera.
*/
#Override
protected void onResume() {
super.onResume();
startCameraSource();
}
The run time exception I am getting is
java.lang.RuntimeException: Fail to connect to camera service
at android.hardware.Camera.<init>(Camera.java:532)
at android.hardware.Camera.open(Camera.java:360)
Any help Regarding this issue because in some devices it is working but in some it is not working I am not able to get the issue.
Always check if the camera is available or not before accesing it.
private Camera mCamera;
/**
* Opens the camera and applies the user settings.
*
* #throws RuntimeException if the method fails
*/
#SuppressLint("InlinedApi")
private Camera createCamera() {
int requestedCameraId = getIdForRequestedCamera(mFacing);
if (requestedCameraId == -1) {
throw new RuntimeException("Could not find requested camera.");
}
if (mCamera != null){
mCamera.release();
mCamera = null;
}
mCamera= Camera.open(requestedCameraId);
if(camera == null){
Toast.makeText(mContext, "Camera service is not available currently.", Toast.LENGTH_LONG.show())
}
//....
}
}
And relsease the camera before onDestroy().
/**
* Releases the resources associated with the camera source, the associated detectors, and the
* rest of the processing pipeline.
*/
#Override
protected void onDestroy() {
super.onDestroy();
if (mPreview != null) {
mPreview.release();
mCamera.release();
mCamera = null;
}
i m running the Google-API connection and functions to gather Information over it in a Activity. Every time i would like to update my stored information(stored in static int variable) i start the Activity by an Intent.
I use a style to make the Activity-Form transparent:
<style name="Theme.Transparent" parent="android:Theme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">#android:color/transparent</item>
<item name="android:windowContentOverlay">#null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
This works fine, but my problem is that every time the Activity "shows-up" the user get interrupted when they are typing or something like that. The Activity "steals" the Focus of Browser-URL Bar while typing as an example.
Is there any way to prevent this behavior? So i need a total silence Activity.
Heres my Google-Actvity Code(Gets Google Mail and Calender Info)
public class MainActivity extends Activity
implements EasyPermissions.PermissionCallbacks {
GoogleAccountCredential mCredential;
private TextView mOutputText;
private Button mCallApiButton;
// ProgressDialog mProgress;
static final int REQUEST_ACCOUNT_PICKER = 1000;
static final int REQUEST_AUTHORIZATION = 1001;
static final int REQUEST_GOOGLE_PLAY_SERVICES = 1002;
static final int REQUEST_PERMISSION_GET_ACCOUNTS = 1003;
static int EMAIL_COUNT = 0;
private static final String PREF_ACCOUNT_NAME = "accountName";
private static final String[] SCOPES = { GmailScopes.GMAIL_LABELS, GmailScopes.GMAIL_READONLY , GmailScopes.MAIL_GOOGLE_COM, CalendarScopes.CALENDAR_READONLY};
/**
* Create the main activity.
* #param savedInstanceState previously saved instance data.
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// mProgress = new ProgressDialog(this);
// mProgress.setMessage("Lade Google-API");
mCredential = GoogleAccountCredential.usingOAuth2(
getApplicationContext(), Arrays.asList(SCOPES))
.setBackOff(new ExponentialBackOff());
getResultsFromApi();
}
/**
* Attempt to call the API, after verifying that all the preconditions are
* satisfied. The preconditions are: Google Play Services installed, an
* account was selected and the device currently has online access. If any
* of the preconditions are not satisfied, the app will prompt the user as
* appropriate.
*/
private void getResultsFromApi() {
if (! isGooglePlayServicesAvailable()) {
acquireGooglePlayServices();
} else if (mCredential.getSelectedAccountName() == null) {
chooseAccount();
} else if (! isDeviceOnline()) {
//mOutputText.setText("No network connection available.");
} else {
new MakeRequestTask(mCredential).execute();
}
}
/**
* Attempts to set the account used with the API credentials. If an account
* name was previously saved it will use that one; otherwise an account
* picker dialog will be shown to the user. Note that the setting the
* account to use with the credentials object requires the app to have the
* GET_ACCOUNTS permission, which is requested here if it is not already
* present. The AfterPermissionGranted annotation indicates that this
* function will be rerun automatically whenever the GET_ACCOUNTS permission
* is granted.
*/
#AfterPermissionGranted(REQUEST_PERMISSION_GET_ACCOUNTS)
private void chooseAccount() {
if (EasyPermissions.hasPermissions(
this, Manifest.permission.GET_ACCOUNTS)) {
String accountName = getPreferences(Context.MODE_PRIVATE)
.getString(PREF_ACCOUNT_NAME, null);
if (accountName != null) {
mCredential.setSelectedAccountName(accountName);
getResultsFromApi();
} else {
// Start a dialog from which the user can choose an account
startActivityForResult(
mCredential.newChooseAccountIntent(),
REQUEST_ACCOUNT_PICKER);
}
} else {
// Request the GET_ACCOUNTS permission via a user dialog
EasyPermissions.requestPermissions(
this,
"This app needs to access your Google account (via Contacts).",
REQUEST_PERMISSION_GET_ACCOUNTS,
Manifest.permission.GET_ACCOUNTS);
}
}
/**
* Called when an activity launched here (specifically, AccountPicker
* and authorization) exits, giving you the requestCode you started it with,
* the resultCode it returned, and any additional data from it.
* #param requestCode code indicating which activity result is incoming.
* #param resultCode code indicating the result of the incoming
* activity result.
* #param data Intent (containing result data) returned by incoming
* activity result.
*/
#Override
protected void onActivityResult(
int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case REQUEST_GOOGLE_PLAY_SERVICES:
if (resultCode != RESULT_OK) {
//mOutputText.setText(
// "This app requires Google Play Services. Please install " +
// "Google Play Services on your device and relaunch this app.");
} else {
getResultsFromApi();
}
break;
case REQUEST_ACCOUNT_PICKER:
if (resultCode == RESULT_OK && data != null && data.getExtras() != null) {
String accountName =
data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
if (accountName != null) {
SharedPreferences settings = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
editor.putString(PREF_ACCOUNT_NAME, accountName);
editor.apply();
mCredential.setSelectedAccountName(accountName);
getResultsFromApi();
}
}
break;
case REQUEST_AUTHORIZATION:
if (resultCode == RESULT_OK) {
getResultsFromApi();
}
break;
}
}
/**
* Respond to requests for permissions at runtime for API 23 and above.
* #param requestCode The request code passed in
* requestPermissions(android.app.Activity, String, int, String[])
* #param permissions The requested permissions. Never null.
* #param grantResults The grant results for the corresponding permissions
* which is either PERMISSION_GRANTED or PERMISSION_DENIED. Never null
There is no way to "stealth run" an activity. Activities are meant for the user to see and interact with, that's their functionality.
If you wish to run something in the background, you would need to use a Service (https://developer.android.com/guide/components/services.html).
Then you can run whatever background API's you want, without the user ever knowing it.