I am attempting to access metadata for an activity from the manifest file.
The manifest looks like this :
<activity
android:name="co.uk.benbun.nvrrclubapp.MainActivity"
android:label="#string/app_name" >
<meta-data android:value="newstag" android:name="NEWS"></meta-data>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
The code to access it, looks like this :
try {
ApplicationInfo ai = getPackageManager().getApplicationInfo(this.getPackageName(), PackageManager.GET_META_DATA);
Bundle bundle = ai.metaData;
String myApiKey = bundle.getString("NEWS");
} catch (NameNotFoundException e) {
Log.e("metadata", "Failed to load meta-data, NameNotFound: " + e.getMessage());
feedTag = "NEWS";
} catch (NullPointerException e) {
Log.e("metadata", "Failed to load meta-data, NullPointer: " + e.getMessage());
feedTag = "NEWS";
}
When I execute the code I always get the nullPointerException.
What am I doing wrong?
The documentation for PackageManager.GET_META_DATA says:
ComponentInfo flag: return the metaData data Bundles that are
associated with a component. This applies for any API returning a
ComponentInfo subclass.
You are calling getApplicationInfo() which returns an ApplicationInfo object. ApplicationInfo does not inherit from ComponentInfo, so this object will not have any meta-data. You need to get the ActivityInfo for your MainActivity in order to get the meta-data (ActivityInfo is a subclass of ComponentInfo).
Related
I've a Bitmap which converted into URI by doing something like this
fun bitmapToUri(ctx: Context, bitmap: Bitmap): Uri {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, ByteArrayOutputStream())
val fileName = "${ctx.getString(R.string.app_name)}-${System.currentTimeMillis()}"
val path = MediaStore.Images.Media.insertImage(ctx.contentResolver, bitmap, fileName, "blah blah")
return Uri.parse(path)
}
So, somewhere I've heard that If your application created some media in my case IMAGE.
You can delete without requiring any permission after API LEVEL - 30 ( Android 11 ). However I've added permission in Manifest
So I'm deleting a file or better Image from URI like this ( Let me know If I can also delete in other ways. Target SDK - 30)
fun deleteUri(context: Context, uri: Uri) {
val contentResolver = context.contentResolver
contentResolver.delete(uri, null, null)
}
Calling this function in some secret place just kidding in MainActivity like this -
uri = bitmapToUri(this#MainActivity, bitmap)
...
// I assure you uri is not null
coroutineScope.launch {
deleteUri(this#MainActivity, uri)
}
...
I'm getting a SecurityException :(
Writing exception to parcel
java.lang.SecurityException: com.example.myapp has no access to content://media/external/images/media/1000000077
at com.android.providers.media.MediaProvider.enforceCallingPermissionInternal(MediaProvider.java:9959)
at com.android.providers.media.MediaProvider.enforceCallingPermission(MediaProvider.java:9856)
at com.android.providers.media.MediaProvider.deleteInternal(MediaProvider.java:5878)
at com.android.providers.media.MediaProvider.delete(MediaProvider.java:5767)
.... and some more
I've also added file provider in Manifest
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"
tools:replace="android:resource" />
</provider>
P.S - I'm testing in Emulator - Pixel 6 API 33, also new on on StackOverflow so please be easy
If you have any question don't hesitate to shoot comment :)
I'm developing an android application which needs to consume rest apis deployed, for now, on an heroku instance...since i got crashes anytime i try to integrate retrofit as http client I've done the following:
Added retrofit2 as dependendcy (didn't choose the latest version in order to avoid potential maturity problems)
compile 'com.squareup.retrofit2:retrofit:2.0.0'
compile 'com.squareup.retrofit2:converter-gson:2.0.0'
compile 'com.google.code.gson:gson:2.6.2'
I coded an example android app, just to check if something has been done wrong in my original app, using http://httpbin.org/ip
public interface HttpBinService
{
public static class Response
{
private String origin;
public Response(String origin) {
this.origin = origin;
}
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
}
#GET("ip")
public Call<Response> getIp ();
}
And the main activity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Retrofit setup
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://httpbin.org")
.addConverterFactory(GsonConverterFactory.create())
.build();
// Service setup
HttpBinService service = retrofit.create(HttpBinService.class);
try {
Call<HttpBinService.Response> call = service.getIp();
Response<HttpBinService.Response> res = call.execute();
if (res.isSuccessful()){
Log.i("PROVARETROFIT", "OK");
((TextView)findViewById(R.id.testo)).setText(res.body().getOrigin());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I did not forget to ask for internet permissions in my manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="it.spich.provaretrofit">
<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">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
But all i got is that application closes unexpectedly. If t execute it in debug, it executes correctly all steps until call execution. LogCat appears to not say anything useful
04-15 09:48:08.281 6491-6491/? I/art: Late-enabling -Xcheck:jni
04-15 09:48:08.367 6491-6491/? W/System: ClassLoader referenced unknown path: /data/app/it.spich.provaretrofit-1/lib/arm64
04-15 09:48:08.387 6491-6491/it.spich.provaretrofit I/HwCust: Constructor found for class android.app.HwCustHwWallpaperManagerImpl
04-15 09:48:08.577 6491-6491/? I/Process: Sending signal. PID: 6491 SIG: 9
Has someone idea of what is happening there?
Not sure why logcat doesn't show anything useful. But when executing it, it is giving an android.os.NetworkOnMainThreadException, which can explain the problem. So as they say in the comments: try using the enque method with a callback, this also allows you to get rid of the try/catch statement. Try to replace the code after // Service setup in your MainActivity with:
HttpBinService service = retrofit.create(HttpBinService.class);
Call<HttpBinService.Response> call = service.getIp();
call.enqueue(new Callback<HttpBinService.Response>() {
#Override
public void onResponse(Call<HttpBinService.Response> call, Response<HttpBinService.Response> response) {
if (response.isSuccessful()){
Log.i("PROVARETROFIT", "OK");
//((TextView)findViewById(R.id.testo)).setText(res.body().getOrigin());
System.out.println(response.body().getOrigin());
} else {
System.out.println("Unsuccesfull");
}
}
#Override
public void onFailure(Call<HttpBinService.Response> call, Throwable t) {
System.out.println("Call failed");
}
});
I built a SyncAdapter for my app so that I could use Google Cloud Messaging to trigger a sync of database to the server. I am using Volley to actually make the network calls and sync the data, but from what I read when wanting to sync your app you should have a SyncAdapter
My issue is that the onPerformSync() doesn't always run. I will fire the GCM and I always get a log stating that it got through the GCM properly, but my log for the onPerformSync() doesn't always fire. Because it does sometimes I would imagine it is set up properly. But I cannot figure out what is happening when it doesn't
onPerformSync()
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.d("onPerformSync", "got to the sync");
}
onMessageReceived() in GCM message handler
#Override
public void onMessageReceived(String from, Bundle data) {
if (from.equals("/topics/global")) {
Log.d("gcm topics", data.getString("message"));
try {
if (data.getString("message").equals("update")) {
Log.d("is update", "is message update");
Account newAccount = new Account(ACCOUNT, ACCOUNT_TYPE);
ContentResolver.requestSync(newAccount, AUTHORITY, data);
}
} catch (NullPointerException e) {
Log.e("GCM", e.toString());
}
} else {
String message = data.getString("message");
createNotification(from, message);
}
}
Creating the account in MainActivity
public static Account createSyncAccount(Context context) {
// Create the account type and default account
Account newAccount = new Account(
ACCOUNT, ACCOUNT_TYPE);
// Get an instance of the Android account manager
AccountManager accountManager =
(AccountManager) context.getSystemService(
ACCOUNT_SERVICE);
/*
* Add the account and account type, no password or user data
* If successful, return the Account object, otherwise report an error.
*/
if (accountManager.addAccountExplicitly(newAccount, null, null)) {
/*
* If you don't set android:syncable="true" in
* in your <provider> element in the manifest,
* then call context.setIsSyncable(account, AUTHORITY, 1)
* here.
*/
ContentResolver.setIsSyncable(newAccount, ArmyContract.CONTENT_AUTHORITY, 1);
ContentResolver.setSyncAutomatically(newAccount, ArmyContract.CONTENT_AUTHORITY, true);
return newAccount;
} else {
/*
* The account exists or some other error occurred. Log this, report it,
* or handle it internally.
*/
Log.e("Account Creation", "Error withou dummy accocunt");
return null;
}
}
syncadapter.xml
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter
xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.clashtoolkit.clashtoolkit"
android:accountType="clashtoolkit.com"
android:userVisible="false"
android:supportsUploading="false"
android:allowParallelSyncs="false"
android:isAlwaysSyncable="true"/>
authenticator.xml
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator
xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="clashtoolkit.com"
android:icon="#mipmap/ic_launcher"
android:smallIcon="#mipmap/ic_launcher"
android:label="#string/app_name"/>
AndroidManifext.xml
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="com.clashtoolkit.clashtoolkit.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.clashtoolkit.clashtoolkit.permission.C2D_MESSAGE" />
<service
android:name="com.clashtoolkit.clashtoolkit.network.AuthenticatorService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator"/>
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="#xml/authenticator" />
</service>
<service
android:name="com.clashtoolkit.clashtoolkit.network.SyncService"
android:exported="true"
android:process=":sync">
<intent-filter>
<action android:name="android.content.SyncAdapter"/>
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="#xml/syncadapter" />
</service>
The problem might be in adding these keys to Bundle data :
// Disable sync backoff and ignore sync preferences. In other words...perform sync NOW!
data.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
data.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
ContentResolver.requestSync(newAccount, AUTHORITY, data);
I have an Activity that handles image files:
if (Intent.ACTION_VIEW.equals(action) && type != null && type.startsWith("image/")) {
Uri imageUri = i.getData();
try {
Bitmap image = MediaStore.Images.Media.getBitmap(getContentResolver(), imageUri);
} catch (Exception e) {
e.printStackTrace();
}
}
This gets me the image in the bitmap, however I also need to get exif data from it. Saving the image using image.compress removes this data.
If I click View in gmail for example, there is no real path that I can use, so I'm stuck at trying to get the exif data. Is there a way to get a byte[] of the data passed into my activity, or get the exif data from a Bitmap object?
Note:
This:
ExifInterface exifData = new ExifInterface(imageUri.getPath());
Does not cause an exception, however I get null for all the tags, and if I try to print the path, I get this:
/my.email#gmail.com/messages/248/attachments/0.1/BEST/false
If I first hit save and then view in gmail, I can successfully retrieve the exif data with the above method, passing imageUri.getPath() to an exif constructor.
If there is no way to make view work, then how can I make it so the user is prompted to use my application only after saving the file to disk? This is how my intent filters look like right now:
<activity android:name=".GameActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
it should be possible to extract the exif data with:
How to use ExifInterface with a stream or URI
Taken from there:
http://android-er.blogspot.co.at/2011/04/read-exif-of-jpg-file.html
//Get Real URL
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = parentActivity.managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String realURL = cursor.getString(column_index);
//Access Exif
ExifInterface exifInterface = new ExifInterface(realURL);
String focal_length = exifInterface.getAttribute(ExifInterface.TAG_FOCAL_LENGTH);
I'm trying to integrate twitter to my app, but I can't seem to get it to work.
This is my code:
public class OAuthForTwitter extends Activity {
private CommonsHttpOAuthConsumer httpOauthConsumer;
private OAuthProvider httpOauthprovider;
public final static String consumerKey = "{removed}";
public final static String consumerSecret = "{removed}";
private final String CALLBACKURL = "sosInternational:///HierBenIkNu";
private Twitter twitter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
doOAuth();
}
/**
* Opens the browser using signpost jar with application specific
* consumerkey and consumerSecret.
*/
private void doOAuth() {
try {
httpOauthConsumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
httpOauthprovider = new DefaultOAuthProvider(
"http://twitter.com/oauth/request_token",
"http://twitter.com/oauth/access_token",
"http://twitter.com/oauth/authorize");
String authUrl = httpOauthprovider.retrieveRequestToken(httpOauthConsumer, CALLBACKURL);
this.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));
} catch (Exception e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Uri uri = intent.getData();
if (uri != null && uri.toString().startsWith(CALLBACKURL)) {
String verifier = uri
.getQueryParameter(oauth.signpost.OAuth.OAUTH_VERIFIER);
try {
// this will populate token and token_secret in consumer
httpOauthprovider.retrieveAccessToken(httpOauthConsumer,
verifier);
// TODO: you might want to store token and token_secret in you
// app settings!!!!!!!!
AccessToken a = new AccessToken(httpOauthConsumer.getToken(),
httpOauthConsumer.getTokenSecret());
// initialize Twitter4J
twitter = new TwitterFactory().getInstance();
twitter.setOAuthConsumer(consumerKey, consumerSecret);
twitter.setOAuthAccessToken(a);
// create a tweet
Date d = new Date(System.currentTimeMillis());
String tweet = "#OAuth working! " + d.toLocaleString();
// send the tweet
twitter.updateStatus(tweet);
} catch (Exception e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
}
When I'm done authenticating on the Twitter site, it should redirect me back to the app.
But instead, I get this Page not found:
I have this in my AndroidManifest:
<intent-filter>
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<category android:name="android.intent.category.BROWSABLE"></category>
<data android:scheme="sosInternational" android:host="HierBenIkNu"></data>
</intent-filter>
How can I go back to my app with the keys i get back?
Ok, it was quite a dumb mistake.
My <intent-filter> wasn't inside an application..
This is how it is now:
<activity
android:name=".OAuthForTwitter"
android:label="#string/app_name"
android:configChanges="orientation|keyboardHidden"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<category android:name="android.intent.category.BROWSABLE"></category>
<data android:scheme="sosInternational" android:host="OAuthForTwitter"></data>
</intent-filter>
</activity>
This kind off works, it just loads the whole app from start.
Isn't there a way to just 'go back' to the last activity without restarting the whole app?
I have solved this. Not exactly the way you have developed, but a slight different way. Here are the steps describing what i did.
Use webview instead of opening it in web browser: One of the key advantage doing it is , you can track the url redirects.
call setWebViewClient method of your webview and override shouldOverrideUrlLoading method of your class, i have used inner class.
You will have url parameter in your method. Check whether it starts with your own call back url or not, (Note: This url contains User Token and user secret that is necessary for authorization).
After you finish your task, you can hide the activity or remove the webView or any thing you desire.
EDIT : This is the oAuth way usually used in web application, so we don't need xAuth way. (In case other community members don't know)
Hope it will help you.
Your callback URL should be "sosInternational://HierBenIkNu" (instead of "sosInternational:///HierBenIkNu") in the Java code.
private final String CALLBACKURL = "sosInternational://HierBenIkNu";