How can I programmatically enable/disable an android screen reader service such as TalkBack?
I am developing a kiosk type application that will be installed on an Android device that will be loaned to visitors while they visit a particular museum. (We are still in the process of determining what device we will use.) The plan is to only allow users to use our app and not have access to the android settings application. However, we'd like to allow users to configure some accessibility settings. When they are finished with the device, we need to restore all the settings to our defaults.
The discussion at the link below has many suggesting launching Android's Settings app. But we don't want users accessing many other settings.
How to Programmatically Enable/Disable Accessibility Service in Android
Only system apps can enable/disable accessibility service programatically.
System apps can directly write in settings secure db to start accessibility service.
Settings.Secure.putString(getContentResolver(),Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "com.packagename/com.packagename.componentname");
Following permission is required to write in settings secure db:
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
For non system apps, only way to start accessibility service is direct them to accessibility settings screen via intent and let user manually start the service :
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
I think there might be a way to do that if you make your app an AccessibilityService (but you would have to enable it manually after install).
Then in your AccessibilityService class, inside onAccessibilityEventmethod you can explore views (recursively) and perform clicks - in the example below it will click on TalkBack item in settings - after that it should toggle the toggle button on next screen (the trick is that you can click on parent not the switch view itself) - I haven't tried this code :)
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
AccessibilityNodeInfo source = event.getSource();
if(event.getEventType()==AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED)
explore(source);
}
private void explore(AccessibilityNodeInfo view){
int count = view.getChildCount();
for(int i=0; i<count; i++){
AccessibilityNodeInfo child = view.getChild(i);
if(!MODE_TALK_BACK_SCREEN){
if(child.getText()!=null && child.getText().toString().toLowerCase().contains("TalkBack")){
child.getParent().performAction(AccessibilityNodeInfo.ACTION_CLICK);
MODE_TALK_BACK_SCREEN=true;
return;
}
}else{
if("ToggleButton".equals(child.getClassName().toString())){ //there ony one toggle button on the screen
child.getParent().performAction(AccessibilityNodeInfo.ACTION_CLICK);
performGlobalAction(GLOBAL_ACTION_BACK);
performGlobalAction(GLOBAL_ACTION_BACK);//need to go back two time - i don't know if that will work :)
return;
}
}
explore(child);
child.recycle();
}
so now if you open accessibility settings with Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); it will perform clicks for you - you would have to somehow cover it with full screen toast or service with view
I'm currently working on automatic airplane mode toggle and it works - so should do the job in your case
take a look on my serviceconfig.xml
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="#string/accessibility_service_description"
android:packageNames="com.android.settings"
android:accessibilityEventTypes="typeWindowStateChanged"
android:accessibilityFlags="flagDefault"
android:accessibilityFeedbackType="feedbackSpoken"
android:notificationTimeout="100"
android:canRetrieveWindowContent="true"
android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity"
/>
From lollipop you can not change all settings that breaks the security
policy. Some of them you may access but you have to take permission
for that. So please don't waste time on that.
Related
We have a commercial application that runs on an Android tablet. It is the activity that is launched on startup, and we have taken steps to prevent the user from access the android system. This includes removing the home and back buttons, as well as settings such as:
ContentResolver cr = getContentResolver();
Settings.Global.putString(cr, "policy_control", "immersive.full=*");
Settings.Secure.putInt(cr, "user_setup_complete", 0);
We have a new requirement to allow the user to connect to WiFi. For this, we would like to access the system wifi settings programatically, via an intent:
Intent intent = new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK);
intent.putExtra("extra_prefs_show_button_bar", true);
intent.putExtra("extra_prefs_set_next_text", (String)null);
startActivity(intent);
This works great - allowing the user to do whatever is needed to establish the wifi connection, including a back button to get back to our app. However, I have found that if you swipe right from the left edge, the Settings navigation drawer opens, and now the user is able to access the android system.
Is there a way to prevent this drawer from opening? Maybe prevent swipe actions while this screen is up, but then to allow them when our application is on top?
We discovered a partial solution. If you include this extra with the intent:
intent.putExtra(":settings:hide_drawer", true);
It will successfully prevent the drawer from opening on this page. However, if you select any of the menu items (such as "Configure Wi-Fi" or "Advanced"), this causes a new intent to be sent, and the drawer is accessible again on these pages. Go back to the original WiFiSettings page from the sub setting pages, and the drawer is disabled again.
Looks like we may have to modify the Android source in order to get the behavior we are looking for.
Please Please read the question complete before marking it as duplicate or vague
On clicking of a button I want to redirect the user to accessibility settings of the android mobile. Where user can click on the accessibility settings of the application. Here is the code that I am using for the same:
Intent dummyIntent = new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivityForResult(dummyIntent, 1);
Problem: When user clicks on, I want that it should redirect back to my application and should not remain on the accessibility screen itself.
It's quite late but i had to make the same stuff. So my suggestion is to use onServiceConnected() overridden method in class that extends AccessibilityService . When user apply accessibility in the settings you can launch intent to desired activity inside onServiceConnected(). But you should keep in mind that after device reboot onServiceConnected() also called, so use some flag to make sure that is not user action.
try this :
Intent dummyIntent = new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS);
ActivityContext.startActivityForResult(dummyIntent, 1);
I'm sure I'm overlooking something in the Settings class documentation. What Intent can open the Settings app in the "Do not disturb" section?
I expected it to be the ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS action, but that is only for the screen which lists which apps have requested DND access.
Update
Looking at the AndroidManifest.xml for the Settings app there is an Activity Settings$ZenModeSettingsActivity already from Android 5.0.
To send the user to the "Do not disturb" screen you can use the action android.settings.ZEN_MODE_SETTINGS like this:
try {
startActivity(new Intent("android.settings.ZEN_MODE_SETTINGS"));
} catch (ActivityNotFoundException e) {
// TODO: Handle activity not found
}
Original answer
It looks like there are no screens in the Settings app (at least on Android 6+7) where you can enable/disable DND. It seems like this is only available through the settings tile (and can be disabled in the dialog when changing the volume).
I have a Samsung S6 (Android 6.0.1) which has this screen, but this is probably some custom Samsung changes. The screen is represented by the class com.android.settings.Settings$ZenModeDNDSettingsActivity which can be started by any app. This might be of help for some people out there.
AndroidManifest.xml for Settings app for Android 6+7:
https://android.googlesource.com/platform/packages/apps/Settings/+/android-6.0.1_r68/AndroidManifest.xml
https://android.googlesource.com/platform/packages/apps/Settings/+/android-7.0.0_r6/AndroidManifest.xml
You have to use the following Intent: ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE and then pass a boolean through EXTRA_DO_NOT_DISTURB_MODE_ENABLED.
Make note that the documentation specifies the following: This intent MUST be started using startVoiceActivity.
I'm developing an Android app for a company where those who will use it are the employees, for this reason the company asked me to develop an application that the user can not close, because if he will not use the smartphone for other purposes, but for this I need the Android native buttons do not interfere with the application.
I've deactivated the button to go back and put the application as Home.
#Override
public void onBackPressed () {
super.onBackPressed ();
}
...
<category android: name = "android.intent.category.HOME" />
However if the user clicks the button that displays open applications, it can exit the application.
I researched a lot before creating resolve this question and realized several attempts to solve this problem.
One. I tried to create the same behavior as the MX Player has, when you use the lock to see a video, the MX Player is always on top of everything, leaving the user to see and click others places. However using this behavior does not i cant see My Dialogs nor Popup and also can not apply a thema, as in my case is not simply an activity is the entire application.
Reference links of my attempt
How to disable Home and other system buttons in Android?
http://www.piwai.info/chatheads-basics/
If anyone knows how to use that behavior MX Player, or if anyone knows any more how to make the user can not close the application, please help me, I know it's not just me who have this problem.
Any help is welcome!
My API is 16 - Android-4.1
Are your target devices rooted? If so, this article goes through the steps to make this possible. What you specifically ask about can be done by modifying the build.prop file to include the following line: qemu.hw.mainkeys=1. This will stop the soft-key navigation bar from ever showing up.
If the device you're running isn't rooted, I don't think that it's possible to do what you're asking.
The best way i found to the user can't access others apps, was to make a service that check which is the top activity, if don't is my then reopen my app.
ActivityManager manager = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> runningTasks = manager.getRunningTasks(1);
if (runningTasks != null && runningTasks.size() > 0) {
ComponentName topActivity = runningTasks.get(0).topActivity;
if (!topActivity.getPackageName().startsWith("com.mypackage.")) {
Log.i("Top Activity", topActivity.getPackageName());
if (LocalCache.getInstance().isForceHome()) {
Intent intent = new Intent(HomeService.this, AuthLoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
handler.postDelayed(this, 500);
}
Old question, but I'm facing exactly same situation:
In-house App
Can't be close
I'm going to set App as a Launcher, and block top-dowm swipe to prevent status bar appear.
I think it's good enough for an in-house App ~
I know there has been lot of discussion for hiding system bar on android 4.0 but no discussions on disabling the functionality of virtual button or status bar or system bar on Android 4.0 tablets?
Is this possible? Can somebody guide me to the right direction?
Thanks!
Try FLAG_FULLSCREEN, it should hide the status bar
http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_FULLSCREEN
I have done a lot of research to design a lock screen and finally found a solution to permanently disable System bars i.e Navigation bar(Back, home, Recent apps soft keys) and the status bar. Android disabled the feature to override System bars except the back button. But there is a little work around to make this work:
Understand and implement screen pinning patiently and you will be successful.
You can create an app to control what all applications you want to implement screen pinning in or you can implement screen pinning directly in the same application you want to pin.
I'm going to show you the later implementation in this article:
1. Firstly your app should be the device owner.
You can do it in several ways and the easiest is to execute the command:
adb shell dpm set-device-owner [yourPackageName]/.[MyDeviceAdminReceiver]
Create a receiver(MyDeviceAdminReceiver) that extends DeviceAdminReceiver. You needn't have any code in here. For more info on Device owner implementation refer this link
http://florent-dupont.blogspot.com/2015/02/10-things-to-know-about-device-owner.html
Register the receiver in the AndroidManifest.xml file this way :
<receiver
android:name=".MyDeviceAdminReceiver"
android:label="#string/app_name"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="#xml/device_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
2. Your onCreate method should look like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lock_screen);
ComponentName deviceAdmin = new ComponentName(this, MyDeviceAdminReceiver.class);
DevicePolicyManager mDpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
if (mDpm.isDeviceOwnerApp(getPackageName())) {
mDpm.setLockTaskPackages(deviceAdmin, new String[]{getPackageName()});
}
if (mDpm.isLockTaskPermitted(this.getPackageName()))
startLockTask();
3.To unpin the screen and make Navigation Bar functional:
Call the function stopLockTask() at a place in your code where you want to unpin. For example in my application, as soon as I verify that the user has typed the correct passcode, I call this function:
if (userInput.length() == 4) {
if (userInput.equals(passcode)) {
userInput = "";
etxtPasscodeDisplay.setText("");
stopLockTask(); // this is what you need
unlockHomeButton(); // A method to show home screen when
passcode is correct
finishAffinity(); //kill other activities
}
Extra Info which usually is required for lockscreens:
1. If your app is the first thing that comes up after boot:
You need a service(StartAtBootService) and a receiver (BootCompletedReceiver) for this.
2. If you want your app to show up after screen lock and unlock
(the power button is pressed to lock and unlock):
Create AEScreenOnOffService that extends service and AEScreenOnOffReceiver that extends BroadcastReceiver to launch your activity when the screen is on.
For a detailed info on everything I mentioned here, refer http://www.sureshjoshi.com/mobile/android-kiosk-mode-without-root/
This is an excellent write up which helped me a lot. Special thanks to the author.
I need at least 10 reputation to post more than two links. As I'm new to stackoverflow I don't have enough reputation so I'm sorry for not being able to share all the links I referred. Will surely update the post once I get access.