I am trying to understand what some of the uses cases are for dynamic permissions in Android. In other words, I am trying to understand why we have addPermission*() API methods and why just having static permissions is not sufficient. There doesn't seem to be much material out there explaining this, so I would appreciate some explanation.
Also, in order to understand what apps do with dynamic permissions, I downloaded some Android apps and started to reverse engineer them and look for the addPermission*() API methods in the source code. I've noticed that there are some apps that implement a wrapper class for PackageManager and I was wondering what the purpose is for doing this. Here is an example to the wrapper classes implemented by these apps, all they do is call the respective method of the PackageManager class:
public class PackageManagerWrapper
extends PackageManager
{
protected PackageManager mInner;
public PackageManagerWrapper()
{
this.mInner = null;
}
public PackageManagerWrapper(Context paramContext)
{
this.mInner = paramContext.getPackageManager();
}
#Inject
public PackageManagerWrapper(PackageManager paramPackageManager)
{
this.mInner = paramPackageManager;
}
public void addPackageToPreferred(String paramString)
{
this.mInner.addPackageToPreferred(paramString);
}
public boolean addPermission(PermissionInfo paramPermissionInfo)
{
return this.mInner.addPermission(paramPermissionInfo);
}
...
}
Thanks a lot!
Apps can define custom permissions in order to protect it's code / data but still let other apps (with the right permission) to use it. While it's easy to think of use cases - like a suite of apps need to share a data/functionality only between them, those can be achieved by using a <permission> tag in manifest. However, this API used only for creating permissions not yet used by any other app:
New permissions must be added before any .apks are installed that use those permissions. Permissions you add through this method are remembered across reboots of the device. If the given permission already exists, the info you supply here will be used to update it.
But still meant to be used by any app that had declared a permission-tree in it's manifest.
So, since it's creating permissions at runtime and therefore cannot be applied to own Activities/Services, we are left only with broadcasts. The only advantage of this API over declaring those permissions in Manifest I can think of is that the user don't need to update the application. So if you are having a suit of apps, with one 'main' app (similar to Google Play), and you want to be able to broadcast to new apps in this suit securely even if the user had not updated your app, you can still get updates over the net and add needed permissions to communicate with the new apps.
For your second question - it's cannot be deducted from you example. There might be several reasons, such as acting as Bridge, or in order to add custom functionality.
Related
Background
Starting from API 25 of Android, apps can offer extra shortcuts in the launcher, by long clicking on them:
The problem
Thing is, all I've found is how your app can offer those shortcuts to the launcher, but I can't find out how the launcher gets the list of them.
Since it's a rather new API, and most users and developers don't even use it, I can't find much information about it, especially because I want to search of the "other side" of the API usage.
What I've tried
I tried reading the docs (here, for example). I don't see it being mentioned. Only the part of other apps is mentioned, but not of the receiver app (the launcher).
The questions
Given a package name of an app, how can I get a list of all of its "app shortcuts" using the new API?
Is it possible to use it in order to request to create a Pinned Shortcut out of one of them?
You need to make yourself the launcher app. After that you can query the packagemanager to get the shortcutinfo for a particular package:
fun getShortcutFromApp(packageName: String): List<Shortcut> {
val shortcutQuery = LauncherApps.ShortcutQuery()
shortcutQuery.setQueryFlags(FLAG_MATCH_DYNAMIC or FLAG_MATCH_MANIFEST or FLAG_MATCH_PINNED)
shortcutQuery.setPackage(packageName)
return try {
launcherApps.getShortcuts(shortcutQuery, Process.myUserHandle())
.map { Shortcut(it.id, it.`package`, it.shortLabel.toString(), it) }
} catch (e: SecurityException) {
Collections.emptyList()
}
}
A full implementation of this can be found here:
https://android.jlelse.eu/nhandling-shortcuts-when-building-an-android-launcher-5908d0bb50d2
Github link to project:
https://github.com/nongdenchet/Shortcuts
LauncherApps is a class provided by the Android framework:
https://developer.android.com/reference/android/content/pm/LauncherApps.html
"Class for retrieving a list of launchable activities for the current user and any associated managed profiles that are visible to the current user, which can be retrieved with getProfiles(). This is mainly for use by launchers. Apps can be queried for each user profile. Since the PackageManager will not deliver package broadcasts for other profiles, you can register for package changes here."
Great Question this was what i was looking for and I get one that might be useful
(Its all about Intent)
https://github.com/googlesamples/android-AppShortcuts
Note: If your app is static its simple to implement.
Updated:::
Here is a link that will show you the difference of dynamic or static shortcuts and its implementation if you like it please up vote.
https://www.novoda.com/blog/exploring-android-nougat-7-1-app-shortcuts/
Once again I require your help stackoverflowers!
I've been working on a SDK and now need to verify that the user granted the permissions for stuff like location or file writing.
Verifying is fine, but I think I should ask for the permission if it's needed. The thing is, I have absolutely no access to any activities. I might use the appContext to check for the permissions, but I can't listen to onRequestPermissionsResult like this.
Is there a clever way to ask for permission from my side or should I ask the developers using my SDK to ask the permissions timely so I can use the feature I (and they) need later on?
Thanks for the help!
Personally I'd prefer SDKs to let me as the developer handle when to ask permissions as I may need to give the user some warning, handle it in advance or do other things before prompting them.
If you look at SDKs like Google Play Location services it leaves the handling of the location permissions to the developer and simply adds a warning to the calls that could fail by stating it may throw a SecurityException.
There is also an annotation they use called android.support.annotation.RequiresPermission which you could use to help users of your SDK. Using this annotation will give you the above mentioned Exception warning / error.
Example from official documentation:
#RequiresPermission(anyOf = {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION})
public abstract Location getLastKnownLocation(String provider);
And as result
I think that you have to declare permissions into documentation and delegate permission-trouble to your sdk users, because library may be part of Model and it mustn't manipulate with UI (permission dialogs)
You can't call permission dialog without activity
I am using Android HockeyAppSDK to deploy updates to an application. I am trying to use the docs to customise the default UpdateManager class to allow updates to be installed automatically, without prompting the user to accept the update.
I am quite unsure of how to handle this. The obvious way (in my mind anyway) is to do the following:
private void checkForUpdates () {
UpdateManager.register (this, Constants.HOCKEY_API_KEY, new UpdateManagerListener() {
public void onUpdateAvailable() {
//I assume stuff will need to be handled here
}
});
}
Has anyone done this before, or can find a way to do it?
Many thanks
After emailing the support team for Hockey, they believe that within their current compiled API it is not possible to perform an update without prompting users to accept.
The whole source would require modification and compilation before working as expected it seems.
You can use UpdateTask from library
I'm trying to create a SyncAdapter for my Android app to show YouTube videos from one specific channel. The videos are public domain so I don't want the user to login, create an account, authenticate themselves, upload data, or use the contacts database. I simply want the SyncAdapter to periodically update my app's database with the newest video metadata from that channel. I already built a ContentProvider to access my database. I do like the fact that the SyncProvider will handle the ability to turn off syncing, scheduling, and retry backoff mechanisms for updating.
I asked earlier if a SyncAdapter was a good choice for my use case, and I was told it was. I watched the Google I/O video, read the docs, read blogs... (see list below). I've been unable to get anything to work. The best I've gotten was to have the SyncAdapter account show up in the global "Accounts & sync settings" but be non-functional. Even if this worked, it would be less than ideal because I prefer the user to not see the account except from inside my app. This would be acceptable if there was no other option, so long as they don't need to access it to set it up as everything would default to automatic once a day syncing.
I even tried to use the SampleSyncAdapter as-is and put breakpoints in the Authentication code sections. Not a single breakpoint is hit so I can't see what triggers the calls or what data is contained. I would have thought I'd at least get that much.
I'm starting to think using a SyncAdapter is a bad idea despite the recommendation. I've yet to find an example that is close to what I want, let alone a tutorial or complete, organized and clear docs. This seems like it should be a common task many apps would want to do.
Please add to this post any good documentation on this use case. I can find none.
Without this, I think it's fair to recommend to everyone to not use SyncAdapters for this use case. I'm not speaking for other use cases here so don't jump on with how it worked for your use case if it's not like mine.
It would also be helpful to know what version of the API level is considered ready for primetime. There's a number of issues posted regarding version numbers. I'm trying to stay as low as possible to get the most users. My current API target is 7.
Here's list of links I've tried to no avail, others may find these more helpful:
http://developer.android.com/resources/samples/SampleSyncAdapter/index.html
http://www.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html
http://naked-code.blogspot.com/2011/05/revenge-of-syncadapter-synchronizing.html
http://www.c99.org/2010/01/23/writing-an-android-sync-provider-part-1/
http://www.c99.org/2010/01/23/writing-an-android-sync-provider-part-2/
http://www.finalconcept.com.au/article/view/android-account-manager-step-by-step
http://www.finalconcept.com.au/article/view/android-account-manager-step-by-step-1
http://www.finalconcept.com.au/article/view/android-account-manager-step-by-step-2
Android SyncAdapter without Authentication vs. Android Service
Why does ContentResolver.requestSync not trigger a sync?
In short the answer is: ContentProvider, AccountManager and SyncAdapter go together. You must have these three pieces, even if they are "dumb".
As stated above, "ContentProvider, AccountManager and SyncAdapter go together".
For your application you can call the following activity the first time your app is loaded to authenticate and start synching automatically:
public class LoginActivity extends AccountAuthenticatorActivity {
private final static String DUMMY_ACCOUNT_NAME = "some_name";
private final static String DUMMY_ACCOUNT_PASS = "some_pass";
private final static String AUTHORITY = "com.android.contacts"; // for example
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Account account = new Account(DUMMY_ACCOUNT_NAME, Constants.ACCOUNT_TYPE);
AccountManager am = AccountManager.get(this);
if (am.addAccountExplicitly(account, DUMMY_ACCOUNT_PASS, null)) {
Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
setAccountAuthenticatorResult(result);
ContentResolver.setSyncAutomatically(account, AUTHORITY, true);
}
finish();
}
}
This works in Android API 5+.
I need to fetch some data over the cloud from my app. I've watched the google IO video on RESTful android apps # http://www.youtube.com/watch?v=xHXn3Kg2IQE&t=43m58s It recommends in the final slides to use a SyncAdapter to integrate with the Android System.
Later I learned that one has to use an Account to implement SyncAdapter. My app does not use an account. Users can freely download data without registration. Can I still use SyncAdapter? Is there a stock dummy account that I could use?
Edit: I do have a content provider for my app so that's not a problem
Edit2: I've just looked at the Weather and Stock apps under Settings -> Accounts & Sync. You can see that they allow syncing, but don't have a remove account button. On the other hand, Google, Facebook and Skype apps allow syncing PLUS they have a remove account button. This means Weather and Stock don't use accounts, whereas Google, Facebook and Skype do.
The tutorials I found # http://ericmiles.wordpress.com/2010/09/22/connecting-the-dots-with-android-syncadapter/ and # http://www.c99.org/2010/01/23/writing-an-android-sync-provider-part-1/ say that one MUST have an account to use Sync Adapter. :S ???
As the Android Developer docs say
Even if your app doesn't use accounts, you still need to provide an authenticator component. If you don't use accounts or server login, the information handled by the authenticator is ignored, so you can provide an authenticator component that contains stub method implementations. You also need to provide a bound Service that allows the sync adapter framework to call the authenticator's methods.
There is an entire article on Creating a Stub Authenticator. I realise that this question is old and an answer was accepted long ago, but I felt that a recent addition to the official docs should be included here.
I have created a contact sync adapter where I don't have a account authorization and or configuration screens. It wasn't that hard. I don't think having to deal with the Android Account stuff was that much of a deal.
Quote from your tutorial link:
The bad news is that there is no
“stock” functionality to give you an
easy way to provide an Account to the
system. However, in the same Sync
Adapter Example that comes with the
SDK there is a lot of code you can
borrow to give you Account
functionality. Unless you desire a
custom credentials screen, you can
heist all the code in the
com.example.android.samplesync.authenticator
package with only a few minor changes.
So it's basically just a copy and paste from the example, that's pretty much what I did and it worked fine.
I don't know for sure but all the adapters that don't have "Remove Account" seems to be built-in ROM adapters on all the devices I've looked at. I'm not sure you have to worried about it.
I keep getting lots of notifications from this question, so I thought I'll share this info. This is how you add SyncAdapter without Account. You can put this in onCreate of MyApplication extends Application class. This assumes you already have a SyncAdapter and ContentProvider implemented. You can do that by following the tutorials listed in the question.
final String ACCOUNT_NAME = "MyApp";
final String ACCOUNT_TYPE = "com.myapp.account";
final String PROVIDER = "com.myapp.provider";
Account appAccount = new Account(ACCOUNT_NAME,ACCOUNT_TYPE);
AccountManager accountManager = AccountManager.get(getApplicationContext());
if (accountManager.addAccountExplicitly(appAccount, null, null)) {
ContentResolver.setIsSyncable(appAccount, PROVIDER, 1);
ContentResolver.setMasterSyncAutomatically(true);
ContentResolver.setSyncAutomatically(appAccount, PROVIDER, true);
}
res/xml/syncadapter.xml
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="#string/provider"
android:accountType="#string/account_type"
android:userVisible="true"
android:supportsUploading="true"
/>
res/xml/authenticator.xml
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="#string/account_type"
android:icon="#drawable/app_icon"
android:smallIcon="#drawable/app_icon"
android:label="#string/app_label"
/>