I am following the Spotify tutorial on android sdk beta22-noconnect-2.20b to just get the groundwork on an app that I want to to write and I am having trouble getting my application to authenticate. I am sure that I have signed my app and inserted the correct fingerprint into the "My Applications" tab on spotify. My URI is correct. I am also fairly certain that I followed the tutorial 100% properly. Every time I run the program I get this error.
I/OpenGLRenderer: Initialized EGL, version 1.4
D/OpenGLRenderer: Swap behavior 1
D/com.spotify.sdk.android.authentication.LoginActivity: https://accounts.spotify.com/authorize?client_id=7c59d84c8b7f4e35b3c85a7a5289db1b&response_type=token&redirect_uri=spotifymixer%3A%2F%2Fcallback&show_dialog=true&scope=user-read-private%20streaming
D/SpotifyAuthHandler: start
D/com.spotify.sdk.android.authentication.LoginActivity: Error authenticating
D/SpotifyAuthHandler: stop
I don't know how to proceed. Could I have used an incorrect signature for the program?
My MainActivity.java:
package com.example.mammo.spotifyplayer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.View;
import com.spotify.sdk.android.authentication.AuthenticationClient;
import com.spotify.sdk.android.authentication.AuthenticationRequest;
import com.spotify.sdk.android.authentication.AuthenticationResponse;
import com.spotify.sdk.android.player.Config;
import com.spotify.sdk.android.player.ConnectionStateCallback;
import com.spotify.sdk.android.player.Error;
import com.spotify.sdk.android.player.Player;
import com.spotify.sdk.android.player.PlayerEvent;
import com.spotify.sdk.android.player.Spotify;
import com.spotify.sdk.android.player.SpotifyPlayer;
public class MainActivity extends Activity implements
SpotifyPlayer.NotificationCallback, ConnectionStateCallback
{
// TODO: Replace with your client ID
private static final String CLIENT_ID = "7c59d84c8b7f4e35b3c85a7a5289db1b";
// TODO: Replace with your redirect URI
private static final String REDIRECT_URI = "spotifymixer://callback";
private Player mPlayer;
private static final int REQUEST_CODE = 1337;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AuthenticationRequest.Builder builder = new AuthenticationRequest.Builder(CLIENT_ID, AuthenticationResponse.Type.TOKEN, REDIRECT_URI);
builder.setScopes(new String[]{"user-read-private", "streaming"});
AuthenticationRequest request = builder.build();
AuthenticationClient.openLoginActivity(this, REQUEST_CODE, request);
}
public void tryAgain(View view){
AuthenticationRequest.Builder builder = new AuthenticationRequest.Builder(CLIENT_ID, AuthenticationResponse.Type.TOKEN, REDIRECT_URI);
builder.setScopes(new String[]{"user-read-private", "streaming"});
AuthenticationRequest request = builder.build();
AuthenticationClient.openLoginActivity(this, REQUEST_CODE, request);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if(requestCode == REQUEST_CODE){
AuthenticationResponse response = AuthenticationClient.getResponse(resultCode, intent);
if(response.getType() == AuthenticationResponse.Type.TOKEN) {
Config playerConfig = new Config(this, response.getAccessToken(), CLIENT_ID);
Spotify.getPlayer(playerConfig, this, new SpotifyPlayer.InitializationObserver() {
#Override
public void onInitialized(SpotifyPlayer spotifyPlayer) {
mPlayer = spotifyPlayer;
mPlayer.addConnectionStateCallback(MainActivity.this);
mPlayer.addNotificationCallback(MainActivity.this);
}
#Override
public void onError(Throwable throwable) {
Log.e("MainActivity", "Could not initialize player: " + throwable.getMessage());
}
});
}
}
}
#Override
protected void onDestroy() {
Spotify.destroyPlayer(this);
super.onDestroy();
}
#Override
public void onPlaybackEvent(PlayerEvent playerEvent) {
Log.d("MainActivity", "Playback event received: " + playerEvent.name());
switch (playerEvent) {
// Handle event type as necessary
default:
break;
}
}
#Override
public void onPlaybackError(Error error) {
Log.d("MainActivity", "Playback error received: " + error.name());
switch (error) {
// Handle error type as necessary
default:
break;
}
}
#Override
public void onLoggedIn() {
Log.d("MainActivity", "User logged in");
mPlayer.playUri(null, "spotify:track:2TpxZ7JUBn3uw46aR7qd6V", 0, 0);
}
#Override
public void onLoggedOut() {
Log.d("MainActivity", "User logged out");
}
#Override
public void onLoginFailed(int i) {
Log.d("MainActivity", "Login failed");
}
#Override
public void onTemporaryError() {
Log.d("MainActivity", "Temporary error occurred");
}
#Override
public void onConnectionMessage(String message) {
Log.d("MainActivity", "Received connection message: " + message);
}
}
My build.gradle (Module:app):
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "com.example.mammo.spotifyplayer"
minSdkVersion 15
targetSdkVersion 24
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
repositories {
mavenCentral()
flatDir {
dirs 'libs'
}
}
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'
})
// This library handles authentication and authorization
compile 'com.spotify.sdk:spotify-auth:beta22-noconnect-2.20b#aar'
// This library handles music playback
compile 'com.spotify.sdk:spotify-player:beta22-noconnect-2.20b#aar'
compile 'com.android.support:appcompat-v7:24.2.1'
testCompile 'junit:junit:4.12'
}
And my AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mammo.spotifyplayer">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Needed for LoginActivity to work -->
<activity
android:name="com.spotify.sdk.android.authentication.LoginActivity"
android:theme="#android:style/Theme.Translucent.NoTitleBar"/>
</application>
</manifest>
Related
I'm storing some images on Parse Server for my Instagram Clone app. When trying to retrieve them using:
ParseFile file = imageToDisplay.getParseFile("image");
byte[] data = file.getData();
everything works just fine as long as there are still some images in cache but if I reinstall the app or try to get data of other users images I get an exception:
2019-12-12 14:24:44.005 15502-15502/com.example.instagramclone E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.instagramclone, PID: 15502
java.lang.IllegalArgumentException: Expected URL scheme 'http' or 'https' but no colon was found
at okhttp3.HttpUrl$Builder.parse(HttpUrl.java:1333)
at okhttp3.HttpUrl.get(HttpUrl.java:916)
at okhttp3.Request$Builder.url(Request.java:165)
at com.parse.ParseHttpClient.getRequest(ParseHttpClient.java:132)
at com.parse.ParseHttpClient.executeInternal(ParseHttpClient.java:68)
at com.parse.ParseHttpClient.execute(ParseHttpClient.java:57)
at com.parse.ParseRequest$3.then(ParseRequest.java:133)
at com.parse.ParseRequest$3.then(ParseRequest.java:130)
at bolts.Task$15.run(Task.java:917)
at bolts.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:105)
at bolts.Task.completeAfterTask(Task.java:908)
at bolts.Task.continueWithTask(Task.java:715)
at bolts.Task.continueWithTask(Task.java:726)
at bolts.Task$13.then(Task.java:818)
at bolts.Task$13.then(Task.java:806)
at bolts.Task$15.run(Task.java:917)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
Same thing happens when I use:
file.getDataInBackground(new GetDataCallback() {
#Override
public void done(byte[] data, ParseException e) {
// More code
}
});
Exception is in the parameter this time. To note saving and retrieving of anything else, so far worked perfectly.
It seems like urls to my ParseFiles are invalid. I checked that for one image with file.getUrl() and got:
undefined/files/78fc29aeab99c3e9ca6b9739efc4245658b7fd0f/087b5781e3ad8f4c3d7f85f039f6f977_image.png
Path without domain. How can I fix that?
Gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.example.instagramclone"
minSdkVersion 23
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation "com.github.parse-community.Parse-SDK-Android:parse:1.22.1"
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.instagramclone">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:name=".ServerStarter"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
android:usesCleartextTraffic="true">
<activity android:name=".UserFeedActivity"></activity>
<activity
android:name=".UserDashboardActivity"
android:label="#string/user_dashboard_activity_label" />
<meta-data
android:name="com.parse.SERVER_URL"
android:value="#string/parse_server_url" />
<meta-data
android:name="com.parse.APPLICATION_ID"
android:value="#string/parse_app_id" />
<meta-data
android:name="com.parse.CLIENT_KEY"
android:value="#string/parse_client_key" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I save images to server using:
class SaveImageTask extends AsyncTask<Intent, Void, Void> {
#Override
protected Void doInBackground(Intent... intents) {
Uri selectedImage = intents[0].getData();
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), selectedImage);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
ParseFile file = new ParseFile("image.png", byteArray);
ImageParseObject image = new ImageParseObject();
image.put("image", file);
image.put("username", ParseUser.getCurrentUser().getUsername());
image.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null)
Toast.makeText(getApplicationContext(), "Image saved successfully!", Toast.LENGTH_LONG).show();
else {
Toast.makeText(getApplicationContext(), "Image saving failed!", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
});
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "Image saving failed!", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
return null;
}
}
Code fragment when the exception is thrown:
Builder parse(#Nullable HttpUrl base, String input) {
int pos = skipLeadingAsciiWhitespace(input, 0, input.length());
int limit = skipTrailingAsciiWhitespace(input, pos, input.length());
// Scheme.
int schemeDelimiterOffset = schemeDelimiterOffset(input, pos, limit);
if (schemeDelimiterOffset != -1) {
if (input.regionMatches(true, pos, "https:", 0, 6)) {
this.scheme = "https";
pos += "https:".length();
} else if (input.regionMatches(true, pos, "http:", 0, 5)) {
this.scheme = "http";
pos += "http:".length();
} else {
throw new IllegalArgumentException("Expected URL scheme 'http' or 'https' but was '"
+ input.substring(0, schemeDelimiterOffset) + "'");
}
} else if (base != null) {
this.scheme = base.scheme;
} else {
throw new IllegalArgumentException(
"Expected URL scheme 'http' or 'https' but no colon was found");
}
...
...
...
Configuartion class
package com.example.instagramclone;
import android.app.Application;
import com.parse.Parse;
import com.parse.ParseACL;
import com.parse.ParseObject;
public class ServerStarter extends Application {
#Override
public void onCreate() {
super.onCreate();
// Enable Local Datastore.
Parse.enableLocalDatastore(this);
ParseObject.registerSubclass(ImageParseObject.class);
// Add your initialization code here
Parse.initialize(new Parse.Configuration.Builder(getApplicationContext())
.applicationId("MY_ACTUAL_APP_ID")
.clientKey("MY_ACTUAL_CLIENT_ID")
.server("http://MY_ACTUAL_DOMAIN/parse/")
.build()
);
// ParseUser.enableAutomaticUser();
ParseACL defaultACL = new ParseACL();
defaultACL.setPublicReadAccess(true);
defaultACL.setPublicWriteAccess(true);
ParseACL.setDefaultACL(defaultACL, true);
}
}
Parse Server Configuartion
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var app = express();
// Specify the connection string for your mongodb database
// and the location to your Parse cloud code
var api = new ParseServer({
databaseURI: "mongodb://root:6fDLIHOCRnkC#127.0.0.1:27017/bitnami_parse",
cloud: "./node_modules/parse-server/lib/cloud-code/Parse.Cloud.js",
appId: "78fc29aeab99c3e9ca6b9739efc4245658b7fd0f",
masterKey: "myActualMasterKey",
serverURL: "http://myActualIP:80/parse",
publicServerURL: "http://myActualIP:80/parse"
});
// Serve the Parse API on the /parse URL prefix
app.use('/parse', api);
var port = 1337;
app.listen(port, function() {
console.log('parse-server running on port ' + port);
});
//Parse Dashboard
var ParseDashboard = require('parse-dashboard');
var dashboard = new ParseDashboard({
apps: [
{
appName: "My Bitnami Parse API",
appId: "78fc29aeab99c3e9ca6b9739efc4245658b7fd0f",
masterKey: "myActualMasterKey",
production: true,
serverURL: "http://myActualIP:80/parse",
publicServerURL: "http://myActualIP:80/parse"
}
],
users: [
{
user: "user",
pass: "myActualPassword"
}
], useEncryptedPasswords: true
});
var allowInsecureHTTP = true;
// Serve the Parse Dashboard on the /parsedashboard URL prefix
app.use('/', dashboard);
var portdash = 4040;
app.listen(portdash, function() {
console.log('parse-dashboard running on port ' + portdash);
});
I have an issue with my Android App. I am asking for permissions to the user to access the READ_EXTERNAL_STORAGE but the bug "permission denial" still makes my app crash.
I have spent hours on it and I have no clue how to fix it.
Here's my logcat:
03-07 15:02:12.387 6800-8893/? E/DatabaseUtils: Writing exception to parcel
java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/images/media from pid=8108, uid=10089 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:605)
at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:480)
at android.content.ContentProvider$Transport.query(ContentProvider.java:211)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112)
at android.os.Binder.execTransact(Binder.java:453)
03-07 15:02:12.391 8108-11729/? E/iu.UploadsManager: Insufficient permissions to process media
java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/images/media from pid=8108, uid=10089 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
at android.os.Parcel.readException(Parcel.java:1602)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:183)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
at android.content.ContentProviderProxy.query(ContentProviderNative.java:421)
at android.content.ContentResolver.query(ContentResolver.java:502)
at android.content.ContentResolver.query(ContentResolver.java:438)
at lqt.a(PG:14)
at com.google.android.libraries.social.autobackup.FingerprintScannerIntentService.onHandleIntent(PG:15)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:66)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:150)
at android.os.HandlerThread.run(HandlerThread.java:61)
My Main activity is:
package com.example.arjufy;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.Manifest;
import android.support.v4.app.ActivityCompat;
import android.widget.Toast;
import android.content.Intent;
import android.support.v4.app.Fragment;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
public class MainActivity extends AppCompatActivity implements MarketPlaceFragment.OnListFragmentInteractionListener {
private FirebaseAuth mFirebaseAuth;
private FirebaseUser mFirebaseUser;
private DatabaseReference mDatabaseReference;
private String mUsername;
private String mPhotoUrl;
public static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 123;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (checkPermissionREAD_EXTERNAL_STORAGE(this)) {
// do your stuff..
// Initialize Firebase Auth
mFirebaseAuth = FirebaseAuth.getInstance();
mFirebaseUser = mFirebaseAuth.getCurrentUser();
if (mFirebaseUser == null) {
// Not signed in, launch the Sign In activity
startActivity(new Intent(this, SplashScreenActivity.class));
finish();
return;
} else {
mUsername = mFirebaseUser.getEmail();
}
mDatabaseReference = FirebaseDatabase.getInstance().getReference();
setContentView(R.layout.activity_main);
Fragment fragment = new MarketPlaceFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.theFragmentFrame, fragment).addToBackStack("MarketPlaceFragment").commit();
}
}
public boolean checkPermissionREAD_EXTERNAL_STORAGE(
final Context context) {
int currentAPIVersion = Build.VERSION.SDK_INT;
if (currentAPIVersion >= android.os.Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(
(Activity) context,
Manifest.permission.READ_EXTERNAL_STORAGE)) {
showDialog("External storage", context,
Manifest.permission.READ_EXTERNAL_STORAGE);
} else {
ActivityCompat
.requestPermissions(
(Activity) context,
new String[] { Manifest.permission.READ_EXTERNAL_STORAGE },
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
}
return false;
} else {
return true;
}
} else {
return true;
}
}
public void showDialog(final String msg, final Context context,
final String permission) {
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
alertBuilder.setCancelable(true);
alertBuilder.setTitle("Permission necessary");
alertBuilder.setMessage(msg + " permission is necessary");
alertBuilder.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions((Activity) context,
new String[] { permission },
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
}
});
AlertDialog alert = alertBuilder.create();
alert.show();
}
#Override
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// do your stuff
} else {
Toast.makeText(MainActivity.this, "GET_ACCOUNTS Denied",
Toast.LENGTH_SHORT).show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions,
grantResults);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.logoff:
FirebaseAuth.getInstance().signOut();
Intent intent1 = new Intent(this, LoginActivity.class);
startActivity(intent1);
return true;
case R.id.profile:
Intent intent2 = new Intent(this, MyProfileActivity.class);
startActivity(intent2);
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onListFragmentInteraction(DatabaseReference reference) {
Intent intent = new Intent(this, ProductDetailViewActivity.class);
intent.putExtra("Product reference", reference.toString());
startActivity(intent);
}
}
My manifest is:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.arjufy">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>``
<activity android:name=".LoginActivity" />
<activity android:name=".SplashScr
eenActivity" />
<activity android:name=".AddProductActivity" />
<activity android:name=".SignUpActivity" />
<activity android:name=".MyProfileActivity" />
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.arjufy"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/path_files" />
</provider>
<activity android:name=".ProductDetailViewActivity" />
</application>
</manifest>
and my gradle is:
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.arjufy"
minSdkVersion 23
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.google.firebase:firebase-auth:16.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.google.android.gms:play-services-auth:16.0.1'
implementation 'com.google.firebase:firebase-storage:16.1.0'
implementation 'com.google.firebase:firebase-database:16.1.0'
implementation 'com.firebaseui:firebase-ui:0.5.3'
implementation 'me.relex:circleindicator:2.1.0#aar'
implementation 'com.getbase:floatingactionbutton:1.10.1'
implementation 'de.hdodenhof:circleimageview:2.2.0'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.google.firebase:firebase-core:16.0.7'
}
Do you have any idea where it might come from?
Thanks a lot for your help.
Very much appreciated.
From Android Developer Documentation
If your app needs a dangerous permission, you must check whether you have that permission every time you perform an operation that requires that permission. Beginning with Android 6.0 (API level 23), users can revoke permissions from any app at any time, even if the app targets a lower API level.
So you need to request permission like this
#TargetApi(23)
public void enableRunTimePermisstion() {
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) &&
(getActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
PackageManager.PERMISSION_GRANTED))
if (getActivity().shouldShowRequestPermissionRationale
(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(getActivity(), "Write storage permission is need for app"
, Toast.LENGTH_LONG).show();
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
} else {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
Toast.makeText(getActivity(), "request permission"
, Toast.LENGTH_LONG).show();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
if (permissions[0].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE) &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(context, "Write external storage granted", Toast.LENGTH_LONG).show();
// >> here you call the method that need the permission
}
} else {
Toast.makeText(getActivity(), "Write external permission denied", Toast.LENGTH_SHORT).show();
enableRunTimePermisstion(); // >> When user request the permission we calling the previous method again.
}
}
Runtime permission has actually taken a new shape in the recent times ... like you need to use a fileprovider, provide Uri and the likes but here is a good library that i have used in the recent times. It works well and hassle free. You can check it out on codepath.
https://guides.codepath.com/android/Managing-Runtime-Permissions-with-PermissionsDispatcher
Cheers.
I'm a newbie to Android development, so apologies in advance if this is a stupid question.
I'm running a simple app that tracks the user's location and store it in a real-time db.
the app works perfectly fine on the emulator, but not for the real devices.
it gets slow with a message showing that "V/FA: Inactivity, disconnecting from service", and when it starts running, nothing is written to the database.
here's my manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.alice.locationfinder3">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
and my build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.alice.locationfinder3"
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0-rc02'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'com.google.firebase:firebase-messaging:12.0.1'
implementation 'com.google.firebase:firebase-database:12.0.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.google.android.gms:play-services:12.0.1'
}
apply plugin: 'com.google.gms.google-services'
Finally, my main activity:
package com.example.alice.locationfinder3;
import android.Manifest;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.location.Criteria;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import java.text.SimpleDateFormat;
import java.util.Date;
import static android.location.Criteria.ACCURACY_FINE;
public class MainActivity extends AppCompatActivity {
private LocationManager locationManager;
private LocationListener locationListener;
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference mDatabase = database.getReference();
double latitude; // latitude
double longitude; // longitude
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationManager = (LocationManager) this.getSystemService(LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setAccuracy(ACCURACY_FINE);
String bestProvider = locationManager.getBestProvider(criteria, true);
locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
Log.d("Location: ", location.toString());
latitude = location.getLatitude();
longitude = location.getLongitude();
long time = location.getTime();
Date date = new Date(time);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String timestamp = sdf.format(date);
writeNewPoint(timestamp, longitude, latitude);
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String s) {
}
};
if(Build.VERSION.SDK_INT < 23)
{
locationManager.requestLocationUpdates(bestProvider, 0, 0, locationListener);
}
else {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},1);
}
else {
locationManager.requestLocationUpdates(bestProvider, 0, 0, locationListener);
}
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Criteria criteria;
criteria = new Criteria();
criteria.setAccuracy(ACCURACY_FINE);
String bestProvider = locationManager.getBestProvider(criteria, true);
if(grantResults.length>0 && grantResults[0]== PackageManager.PERMISSION_GRANTED)
{
if(ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
{
locationManager.requestLocationUpdates(bestProvider, 0, 0, locationListener);
}
}
}
private void writeNewPoint(String timestamp, double longitude, double latitude) {
Point point = new Point(longitude, latitude);
mDatabase.child("points").child(timestamp).setValue(point);
}
}
Snapshot from logcat:
09-02 16:05:11.150 28873-28906/com.example.alice.locationfinder3 V/FA: Inactivity, disconnecting from the service
09-02 16:05:11.170 28873-28958/com.example.alice.locationfinder3 I/FirebaseCrash: Sending crashes
09-02 16:05:31.195 28873-28873/com.example.alice.locationfinder3 D/Location:: Location[gps XX.7591,XX.6441 hAcc=64 et=+16h53m5s212ms alt=604.5306458863317 vel=0.14499298 bear=124.898796 vAcc=??? sAcc=??? bAcc=??? {Bundle[mParcelledData.dataSize=40]}]
0
Again, this works fine with the emulator, runs and stores to the db.
But it fails with real devices.
Thanks.
Try following these steps.The reasoning is explained in this post: V/FA: Inactivity, disconnecting from the service
Steps:
1)Uninstall the app from your mobile/emulator.
2)Then go to the File option in the main menubar in the android studio.
3)Then click on Invalidatecasha/restart.
I have the following problem when I run the 'app' (Android studio emulator):
Error:Execution failed for task ':app:javaPreCompileDebug'.
> Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor. Please add them to the annotationProcessor configuration.
- butterknife-7.0.1.jar (com.jakewharton:butterknife:7.0.1)
Alternatively, set android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true to continue with previous behavior. Note that this option is deprecated and will be removed in the future.
See https://developer.android.com/r/tools/annotation-processor-error-message.html for more details.
My Graddle-App Level:
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '26.0.2'
defaultConfig {
applicationId "com.hhhhh.android"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation 'com.google.firebase:firebase-database:11.0.4'
implementation 'com.google.firebase:firebase-auth:11.0.4'
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:25.2.0'
compile 'com.android.support:design:25.0.1'
compile 'com.jakewharton:butterknife:7.0.1'
}
apply plugin: 'com.google.gms.google-services'
The error disappears when I switch to the version:
compile 'com.jakewharton:butterknife:8.7.0'
But it generates more problems in my LogginActivity:
package com.sourcey.materiallogindemo;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.content.Intent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import butterknife.ButterKnife;
import butterknife.Bind;
public class LoginActivity extends AppCompatActivity {
private static final String TAG = "LoginActivity";
private static final int REQUEST_SIGNUP = 0;
#Bind(R.id.input_email) EditText _emailText;
#Bind(R.id.input_password) EditText _passwordText;
#Bind(R.id.btn_login) Button _loginButton;
#Bind(R.id.link_signup) TextView _signupLink;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
_loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
login();
}
});
_signupLink.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Start the Signup activity
Intent intent = new Intent(getApplicationContext(), SignupActivity.class);
startActivityForResult(intent, REQUEST_SIGNUP);
finish();
overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out);
}
});
}
public void login() {
Log.d(TAG, "Login");
if (!validate()) {
onLoginFailed();
return;
}
_loginButton.setEnabled(false);
final ProgressDialog progressDialog = new ProgressDialog(LoginActivity.this,
R.style.AppTheme_Dark_Dialog);
progressDialog.setIndeterminate(true);
progressDialog.setMessage("Authenticating...");
progressDialog.show();
String email = _emailText.getText().toString();
String password = _passwordText.getText().toString();
// TODO: Implement your own authentication logic here.
new android.os.Handler().postDelayed(
new Runnable() {
public void run() {
// On complete call either onLoginSuccess or onLoginFailed
onLoginSuccess();
// onLoginFailed();
progressDialog.dismiss();
}
}, 3000);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_SIGNUP) {
if (resultCode == RESULT_OK) {
// TODO: Implement successful signup logic here
// By default we just finish the Activity and log them in automatically
this.finish();
}
}
}
#Override
public void onBackPressed() {
// Disable going back to the MainActivity
moveTaskToBack(true);
}
public void onLoginSuccess() {
_loginButton.setEnabled(true);
finish();
}
public void onLoginFailed() {
Toast.makeText(getBaseContext(), "Login failed", Toast.LENGTH_LONG).show();
_loginButton.setEnabled(true);
}
public boolean validate() {
boolean valid = true;
String email = _emailText.getText().toString();
String password = _passwordText.getText().toString();
if (email.isEmpty() || !android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
_emailText.setError("enter a valid email address");
valid = false;
} else {
_emailText.setError(null);
}
if (password.isEmpty() || password.length() < 4 || password.length() > 10) {
_passwordText.setError("between 4 and 10 alphanumeric characters");
valid = false;
} else {
_passwordText.setError(null);
}
return valid;
}
}
With 8.7.0:
Annotation processors must be explicitly declared now
Do what it says
Add the second line
compile 'com.jakewharton:butterknife:8.7.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.7.0'
With 8.7.0 ... it generates more problems in my LogginActivity:
You are importing the wrong class...
Annotate fields with #BindView
That changed at Version 8.0
See the website for usage and the latest version. http://jakewharton.github.io/butterknife/
import butterknife.BindView;
..
#BindView(R.id...)
you can solve this issue by simply adding this to your app level gradle file
android{
....
defaultConfig{
....
javaCompileOptions {
annotationProcessorOptions {
includeCompileClasspath true
}
}
}
Hope its worked
Just add this line:
annotationProcessor 'com.jakewharton:butterknife-compiler:7.0.1'
in your dependencies like:
dependencies {
//...
compile 'com.jakewharton:butterknife:7.0.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:7.0.1'
}
Check this out for more details.
You can try :
// butter knife
compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
Otherwise you can try
https://github.com/avast/android-butterknife-zelezny
to auto gencode from butterknife.
I hope it can help your problem!
try this ,you need to add the annotation along with ButterKnife library..
Butterknife library
compile 'com.jakewharton:butterknife:8.8.1'
annotation for butterknife
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
I want to add leak canary to a test project. I created a project and did the steps from this video: https://www.youtube.com/watch?v=2VKBjlHtKMY
When I'm trying wrongWay(), the message "Dumping Memory app will freeze" is appearing in the emulator Nexus_5X_API_23. When I'm trying rightWay(), the same message is appearing too. There is no message "Dumping Memory app will freeze" in video when author using rightWay().
I cant understand why?
Where can I find a good tutorial about Leak Canary or other Leak Memory library.
So build.gradle is:
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "24.0.1"
defaultConfig {
applicationId "com.example.vopolski.myleakcanary"
minSdkVersion 15
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.2.0'
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.vopolski.myleakcanary">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme"
android:name=".LeakCanaryApplication">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
LeakCanaryApplication.java
package com.example.vopolski.myleakcanary;
import android.app.Application;
import android.content.Context;
import android.os.SystemClock;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;
public class LeakCanaryApplication extends Application {
private RefWatcher refWatcher;
#Override
public void onCreate() {
super.onCreate();
refWatcher = LeakCanary.install(this);
}
public static RefWatcher getRefWatcher(Context context) {
LeakCanaryApplication application =
(LeakCanaryApplication) context.getApplicationContext();
return application.refWatcher;
}
}
MainActivity.java
package com.example.vopolski.myleakcanary;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;
import android.app.Application;
public class MainActivity extends AppCompatActivity {
private String msg;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rightWay();
}
private void rightWay() {
new MyThread().start();
}
private class MyThread extends Thread {
#Override
public void run() {
while (true) {
SystemClock.sleep(1000);
}
}
}
private void wrongWay() {
new Thread() {
#Override
public void run() {
while (true){
SystemClock.sleep(1000);
}
}
}.start();
}
}
I think you should add the following to your Activity onDestroy method
RefWatcher refWatcher = MyApplication.getRefWatcher(this);
refWatcher.watch(this);
You can refer to following URL https://github.com/square/leakcanary/wiki/FAQ
I think you're doing the rightWay() wrong.
MyThread should be static, otherwise it's a non-static inner class, and implicitly references the outer class Activity. The thread runs forever, so the activity won't be GCed. This is a memory leak.