Q: Android Dev - Enable a Manifest-Disabled Broadcast-Receiver from Activity - java

I have a BroadcastReceiver which is registered in my Manifest file as "Disabled"..
It listens for a System-based Broadcast, and then fires.. but I don't want my BroadcastReceiver to actually be Enabled and Listening until I tell it to (for example, a user-set Preference within my app which makes it Enabled)..
From what i've gathered by searching, I've found the following 2 things that might work:
Context.getApplicationContext().registerReceiver
(LocationReceiver.class,
"android.intent.action.PROVIDER_CHANGED");
and
setComponentEnabledSetting
(LocationReceiver.class,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
0);
But neither of them are working..
For the first one, it says "the non-static method getApplicationContext cannot be referenced from a static context, and the second one I think I may just not be referencing the first argument correctly (ComponentName).
Can anybody give me some insight?
Thanks!

Try this hope it will work
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP)

Related

Android: Uri Access Life Time from one activity to another

I have a helper method for choosing images and videos, let's call it Activity B.
So, this is how it works:
// were in Activity A
// user wants to choose a video
startActivityB(callbacks);
------------------------------------
// were in Activity B now
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("video/*");
chooseVideoLauncher.launch(intent);
------------------------------------
// were in chooseVideoLauncher now
Uri videoURI = ...;
callbacks.passVideoURI(videoURI); // this way, Activity A gets the videoURI
// do some more things...
finish(); // so the helper activity B is finished now, as the video is chosen already
------------------------------------
// were in activity A again, but now we have the videoURI
// user clicked a button: "Upload video"
uploadVideo(videoURI);
This is the error I get:
java.lang.SecurityException: Permission Denial: opening provider com.miui.gallery.provider.GalleryOpenProvider from ProcessRecord{f5899ab 29899:com.xxx} (pid=xxx, uid=xxx) that is not exported from UID xxx
I have googled the error and found this SO thread: here
#CommonsWare explains the error in a comment and links his blog post: Uri Access Lifetime: Shorter Than You Might Think
So the error happens because the helper Activity B chose the file, so the access is tied to Activity B. No other activity has access, and as soon as Activity B is destroyed (what happens in my code), the access to videoURI is completely gone. So when I later try to upload the video, it throws this error.
I tried these solutions:
Create a local copy of the video and pass that copy to Activity A. This works, but is a bad solution. For longer videos the app crashes with a memory overflow. So it's not an option.
Setting the flags #CommonsWare mentioned. So the code looks like this:
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("video/*");
intent.setFlags(FLAG_GRANT_READ_URI_PERMISSION);
intent.setFlags(FLAG_GRANT_WRITE_URI_PERMISSION);
chooseVideoLauncher.launch(intent);
But this doesn't seem to change anything. The error message remains exactly the same. Am I setting them wrong?
#CommonsWare says using a service would also be a solution. I would prefer not to create a service purely for fixing this permission error. If there's no other solution, I will of course.
But is there no way to grant Activity A permission to that Uri as well?
The best solution, by far, is to combine Activity A and Activity B into a single activity. Use fragments or composables for separate screens.
Setting the flags #CommonsWare mentioned. So the code looks like this:
You would not set the flags on the ACTION_PICK Intent. Instead, Activity B needs to start Activity A (in addition to finish()). You would put the Uri into the "data" facet of the Intent (e.g., via setData()), and you would put the flags on that Intent. You would also need something like FLAG_ACTIVITY_REORDER_TO_FRONT or something to avoid having two copies of Activity A on the back stack.
For the second way Set the flags to get the long lifetime, you can try to add the following code, to get the permission, then start the activity
val contentResolver = applicationContext.contentResolver
val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
// Check for the freshest data.
contentResolver.takePersistableUriPermission(uri, takeFlags)

How to move from a AbilitySlice to a Ability in HarmonyOS?

I am trying to move from an AbilitySlice to an Ability. I tried the below code,
But was it not working as expected.
Operation systemOperation = new Intent.OperationBuilder()
.withBundleName(getBundleName())
.withAbilityName(MainAbility.class.getSimpleName())
.build();
intent.setOperation(systemOperation);
startAbility(intent);
for moving from an AbilitySlice to Ability in Harmony OS?
Try to Delete Simple from getSimpleName. Like following:
Operation systemOperation = new Intent.OperationBuilder()
.withBundleName(getBundleName())
.withAbilityName(MainAbility.class.getName())
.build();
intent.setOperation(systemOperation);
startAbility(intent);
"Not working as expected" generally is not a valid error description. I'd suspect the AbilitySlice might belong to MainAbility and the whole operation might therefore be pointless, as navigation from A to B could not happen. The example which #Gowtham provided has one small difference (which appears to consider the device on which to launch the Intent with Super Device):
.withDeviceId("")
Have you ever tried to start anything else but MainAbility?
I see that you have mentioned that the package name of your target ability is different than the package name of your ability slice in your reply to #Martin.
Then, you need to make sure the bundleName(or package name) specified in the Intent's Operation builder is having the target ability's package name and not the calling ability's/abilityslice's package name.
Operation systemOperation = new Intent.OperationBuilder()
.withBundleName("enter_package_name_of target_ability_here")
.withAbilityName(MainAbility.class.getName())
.build();
intent.setOperation(systemOperation);
startAbility(intent);

What is the alternate for clearApplicationUserData() from PackagerManager class in android?

I have a requirement for clearing application user data and cache data for provided package name. Previously I was using clearApplicationUserData(), deleteApplicationCacheFiles() methods from PackageManager class. But now both are deprecated or hidden (#hide) in android 11. What's the alternative?
Below is my previous way of doing it -
PackageManager pm = mContext.getPackageManager();
//observer is ->IPackageDataObserver
pm.clearApplicationUserData(packageName, observer);
and
PackageManager pm = mContext.getPackageManager();
//observer is ->IPackageDataObserver
pm.deleteApplicationCacheFiles(packageName, observer);
What would be the alternate solution for the same? I know there are methods like -
(mContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).clearApplicationUserData()
//for clearing current application user data
and
mContext.getCacheDir().deleteRecursively()
//for clearing current application cache data
But in my case, it is another application and I will provide the package name.
I was reading about clearApplicationUserData() from DevicePolicyManager class, but not sure how it works. Can anyone help me here?

Get Chosen App from Intent.createChooser

I am trying to capture the result of Intent.createChooser to know which app a user selected for sharing.
I know there have been a lot of posts related to this:
How to know which application the user chose when using an intent chooser?
https://stackoverflow.com/questions/6137592/how-to-know-the-action-choosed-in-a-intent-createchooser?rq=1
How to get the user selection from startActivityForResult(Intent.createChooser(fileIntent, "Open file using..."), APP_PICKED);?
Capturing and intercepting ACTION_SEND intents on Android
but these posts are somewhat old, and I am hoping that there might be some new developments.
I am trying to implement a share action without having it be present in the menu. The closest solution to what I want is provided by ClickClickClack who suggest implementing a custom app chooser, but that seems heavy handed. Plus, it seems like there might be some Android hooks to get the chosen app, like the ActivityChooserModel.OnChooseActivityListener.
I have the following code in my MainActivity, but the onShareTargetSelected method is never getting called.
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, shareMessage());
sendIntent.setType("text/plain");
Intent intent = Intent.createChooser(sendIntent, getResources().getText(R.string.share_prompt));
ShareActionProvider sap = new ShareActionProvider(this);
sap.setShareIntent(sendIntent);
sap.setOnShareTargetSelectedListener(new ShareActionProvider.OnShareTargetSelectedListener() {
#Override
public boolean onShareTargetSelected(ShareActionProvider source, Intent intent) {
System.out.println("Success!!");
return false;
}
});
startActivityForResult(intent, 1);
As of API level 22 it is now actually possible. In Android 5.1 a method (createChooser (Intent target, CharSequence title, IntentSender sender)) was added that allows for receiving the results of the user's choice. When you provide an IntentSender to createChooser, the sender will be notified by the chooser dialog with the ComponentName chosen by the user. It will be supplied in the extra named EXTRA_CHOSEN_COMPONENT int the IntentSender that is notified.
I am trying to capture the result of Intent.createChooser to know which app a user selected for sharing.
That is not possible.
Other "choosing" solutions, like ShareActionProvider, may offer more. I have not examined the Intent handed to onShareTargetSelected() to see if it contains the ComponentName of the chosen target, though the docs suggest that it should.
And, if for some reason it does not, you are welcome to try to fork ShareActionProvider to add the hooks you want.
The reason why createChooser() cannot be handled this way is simply because the "choosing" is being done by a separate process from yours.
I have the following code in my MainActivity, but the onShareTargetSelected method is never getting called.
ShareActionProvider goes in the action bar. You cannot just create an instance, call a couple of setters, and expect something to happen.

Use system PIN dialog in Android application

Background
I am trying to write an application which works like described below.
When user start application it check if user have registered PIN on his device.
If user have registered PIN, application must show button "Continue with PIN".
When user press on button "Continue with PIN" system standard PIN dialog must appears.
User enter his PIN and press "Continue" button.
After System must check if entered PIN is correct or no and continue working.
Searches
I have made some searches and found some articles on stackoverflow and other internet sources which say "There is no way to develop a new custom unlock mechanism on a non-rooted phone." or "I would be surprised if you could, because then you would be probably able to steal the pin code, and I don't think anyone would want that.".
Also I have watched some video tutorials like Tutorial: Android Internals - Building a Custom ROM, Pt. 1 of 2 and Tutorial: Android Internals - Building a Custom ROM, Pt. 2 of 2.
EDITED
I have made some searches today and found a very interesting thing, I think I am on a right way to the solution, and I want to share my ideas with you. So looking in android sources I found an interesting files ChooseLockPassword.java (packages\apps\Settings\src\com\android\settings) and LockPatternUtils.java (*frameworks\base\core\java\com\android\internal\widget*) now I am interest in:
Question
How can I call LockPatternUtils class function from my code ? Or Why I cant see that function in Eclipse ?
Decision
So I think that the only way to get access to the Android system PIN dialog is to root the phone make some changes in the system files and use system PIN dialod
Question
Can somebody provide me useful links about getting access to the system PIN dialog in the rooted phone.
Am I on a right way and can I solve my problem in this way?
If anybody encountered such problem please help me to solve.
Any Solutions?
Okay, I have solved this problem and now I want to share my solution with you.
At first as I told I have android sources so I have made some changes in android sources to get access to the PIN and Pattern dialogs. And here they are:
in ~\AndroidSources\pakages\apps\Settings\AndroidManifest.xml I have changed following lines of code
<activity android:name="ConfirmLockPattern"
android:exported="true"> // This line was added by me.
</activity>
<activity android:name="ConfirmLockPassword"
android:exported="true" // This line was added by me.
android:them="#android:style/Them.NoTitleBar">
</activity>
<activity android:name="ChooseLockPattern"
android:exported="true" // This line was added by me.
android:label="#string/lockpattern_change_lock_pattern_label">
</activity>
This modifications allow me to call "ConfirmLockPattern", "ConfirmLockPassword" and "ChooseLockPattern" activities from my own application. After I compile android Source codes and launch system.img on my emulator.
In my application I have write following functions in order to call "ConfirmLockPattern" or "ChooseLockPattern" activities:
/**
* Show PIN/Password confirmation dialog.
*/
void ShowConfirmLockPINActivity() {
CustomLog.i(TAG, "Show Confirm Lock PIN Activity");
Intent intent = new Intent(Intent.ACTION_RUN);
intent.setComponent(new ComponentName("com.android.settings",
"com.android.settings.ConfirmLockPassword"));
startActivityForResult(intent, mRequestCode);
} /* ShowConfirmLockPINActivity() */
/**
* Show set PIN/Password dialog.
*/
void ShowSetLockPINActivity() {
CustomLog.i(TAG, "Show Set Lock PIN Activity");
Intent intent = new Intent(Intent.ACTION_RUN);
intent.setComponent(new ComponentName("com.android.settings",
"com.android.settings.ChooseLockPassword"));
startActivityForResult(intent, mRequestCode);
} /* ShowSetLockPINActivity() */
/**
* Show Pattern Confirmation dialog.
*/
void ShowSetLockPatternActivity() {
CustomLog.i(TAG, "Show Set Lock Pattern Activity");
Intent intent = new Intent(Intent.ACTION_RUN);
intent.setComponent(new ComponentName("com.android.settings",
"com.android.settings.ConfirmLockPattern"));
startActivityForResult(intent, mRequestCode);
} /* ShowSetLockPatternActivity() */
Here are some considerations regarding your question.
Diving deep into Android's code is not very good idea in this particular case, since verifying PIN code is an important security point and its mechanism must be hidden and well protected to avoid any malicious intentions.
Thus, the actions you want to perform (ask for PIN and then check it against real PIN) are prohibited and would look like an intrusion. So, you shouldn't try to get an access to the storage of user passwords.
It would be more correct to try launching standard PIN screen via some Intent and ask it to make all job for you. However, a brief investigation didn't give me any results in this direction; perhaps, you'll find something.
Modifying the ROM is obviously dead-end - no one will flash the phone to install one app. Requiring rooted phone is a bit better, there are apps that cannot run on non-rooted phone, but still it forwards us back to the point #2 (intrusion).
Users may disable PIN check and there are devices with no SIM.
So, according to the all mentioned I'd suggest you think of different verification method for your app.
Since API level 21 there is KeyguardManager.createConfirmDeviceCredentialIntent that can be used to authenticate current user with the device lock pin.
See the usage example.

Categories