Detect if 'High contrast' is enabled in Android accessibility settings - android

How can I detect if 'High Contrast' setting (available on Android 5.0+) is enabled in Accessibility settings?

In the AccessibilityManager class (see source here) you have a public method called isHighTextContrastEnabled that you can use to get your information:
/**
* Returns if the high text contrast in the system is enabled.
* <p>
* <strong>Note:</strong> You need to query this only if you application is
* doing its own rendering and does not rely on the platform rendering pipeline.
* </p>
*
* #return True if high text contrast is enabled, false otherwise.
*
* #hide
*/
public boolean isHighTextContrastEnabled() {
synchronized (mLock) {
IAccessibilityManager service = getServiceLocked();
if (service == null) {
return false;
}
return mIsHighTextContrastEnabled;
}
}
So in your code, you can access this method by doing so (if you're in an Activity):
AccessibilityManager am = (AccessibilityManager) this.getSystemService(Context.ACCESSIBILITY_SERVICE);
boolean isHighTextContrastEnabled = am.isHighTextContrastEnabled();

#alxscms' answer may be right but it does not help me So I found an alternative way to check High contrast text is Enabled or not in android.
Below function will return true if HighContrastText is enabled in user phone and otherwise return false.
Below function is checked in all android phones and it's working.
public static boolean isHighContrastTextEnabled(Context context) {
if (context != null) {
AccessibilityManager am = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
Method m = null;
if (am != null) {
try {
m = am.getClass().getMethod("isHighTextContrastEnabled", null);
} catch (NoSuchMethodException e) {
Log.i("FAIL", "isHighTextContrastEnabled not found in AccessibilityManager");
}
}
Object result;
if (m != null) {
try {
result = m.invoke(am, null);
if (result instanceof Boolean) {
return (Boolean) result;
}
} catch (Exception e) {
Log.i("fail", "isHighTextContrastEnabled invoked with an exception" + e.getMessage());
}
}
}
return false;
}
I hope this can help many more others.

we can check highContrast fonts like this
public boolean isHighTextContrastEnabled(Context context) {
return Settings.Secure.getInt(context.getContentResolver(), "high_text_contrast_enabled", 0) == 1;
}

Related

PackageManager check of isEphemeralDisabled causes a deadlock on Android 7.1

private boolean isEphemeralAllowed(
Intent intent, List<ResolveInfo> resolvedActivities, int userId,
boolean skipPackageCheck) {
// Short circuit and return early if possible.
if (isEphemeralDisabled()) {
return false;
}
final int callingUser = UserHandle.getCallingUserId();
if (callingUser != UserHandle.USER_SYSTEM) {
return false;
}
if (mEphemeralResolverConnection == null) {
return false;
}
if (intent.getComponent() != null) {
return false;
}
if ((intent.getFlags() & Intent.FLAG_IGNORE_EPHEMERAL) != 0) {
return false;
}
if (!skipPackageCheck && intent.getPackage() != null) {
return false;
}
final boolean isWebUri = hasWebURI(intent);
private boolean isEphemeralDisabled() {
// ephemeral apps have been disabled across the board
if (DISABLE_EPHEMERAL_APPS) {
return true;
}
// system isn't up yet; can't read settings, so, assume no ephemeral apps
if (!mSystemReady) {
return true;
}
// we can't get a content resolver until the system is ready; these checks must happen last
final ContentResolver resolver = mContext.getContentResolver();
if (Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0) {
return true;
}
return Secure.getInt(resolver, Secure.WEB_ACTION_ENABLED, 1) == 0;
}
For Android 7.0, DISABLE_EPHEMERAL_APPS default is true
private static final boolean DISABLE_EPHEMERAL_APPS = true;
But in Android 7.1, Google enabled Instant apps support: https://android.googlesource.com/platform/frameworks/base.git/+/7ef97b6624054fff0d712d85336a45eee70bcc3f%5E%21/#F0
for isEphemeralAllowed method, if call resolveIntent, most of intents will call isEphemeralAllowed method, so this will cause PackageManager service user binder call settingProvider, and will probability cause a deadlock.

how to build a inputConnection between edit text that inside the input method service and the service

I am writing an IME (InputMethodService) and I have an edit text that in the IME itself, but when I want type text into the edit text , the edit text can't get focused and what I type just go to another edit text outside the IME. how can I make the edit text inside the IME work like normal edit text
The way I solved this was by keeping two input connections, one to the original textfield that the user WAS editing, and another to the textfield inside the keyboard. More on the second one later. The first one you should already have, it's where the keyboard sends all of its commands. In my case it was called mIC. So I created another InputConnection variable called mOtherIC on my class that had the InputConnection, and introduced a new method called getIC() which just returned the appropriate one of those two InputConnections to be using at the time (controlled by a boolean in my case, true meant use the textfield in the keyboard, false meant use the textfield that originally presented the keyboard). Every time I had previously accessed mIC, I replaced it with getIC() so it would seamlessly be able to send input to the correct input connection.
The InputConnection for the textfield in the keyboard is the interesting one here, I essentially had to copy the internal Android EditableInputConnection into my own CustomInputConnection class:
public class CustomInputConnection extends BaseInputConnection {
private static final boolean DEBUG = false;
private static final String TAG = "CustomInputConnection";
private final TextView mTextView;
// Keeps track of nested begin/end batch edit to ensure this connection always has a
// balanced impact on its associated TextView.
// A negative value means that this connection has been finished by the InputMethodManager.
private int mBatchEditNesting;
public CustomInputConnection(TextView textview) {
super(textview, true);
mTextView = textview;
}
#Override
public Editable getEditable() {
TextView tv = mTextView;
if (tv != null) {
return tv.getEditableText();
}
return null;
}
#Override
public boolean beginBatchEdit() {
synchronized(this) {
if (mBatchEditNesting >= 0) {
mTextView.beginBatchEdit();
mBatchEditNesting++;
return true;
}
}
return false;
}
#Override
public boolean endBatchEdit() {
synchronized(this) {
if (mBatchEditNesting > 0) {
// When the connection is reset by the InputMethodManager and reportFinish
// is called, some endBatchEdit calls may still be asynchronously received from the
// IME. Do not take these into account, thus ensuring that this IC's final
// contribution to mTextView's nested batch edit count is zero.
mTextView.endBatchEdit();
mBatchEditNesting--;
return true;
}
}
return false;
}
// #Override
// protected void reportFinish() {
// super.reportFinish();
//
// synchronized(this) {
// while (mBatchEditNesting > 0) {
// endBatchEdit();
// }
// // Will prevent any further calls to begin or endBatchEdit
// mBatchEditNesting = -1;
// }
// }
#Override
public boolean clearMetaKeyStates(int states) {
final Editable content = getEditable();
if (content == null) return false;
KeyListener kl = mTextView.getKeyListener();
if (kl != null) {
try {
kl.clearMetaKeyState(mTextView, content, states);
} catch (AbstractMethodError e) {
// This is an old listener that doesn't implement the
// new method.
}
}
return true;
}
#Override
public boolean commitCompletion(CompletionInfo text) {
if (DEBUG) Log.v(TAG, "commitCompletion " + text);
mTextView.beginBatchEdit();
mTextView.onCommitCompletion(text);
mTextView.endBatchEdit();
return true;
}
/**
* Calls the {#link TextView#onCommitCorrection} method of the associated TextView.
*/
#Override
public boolean commitCorrection(CorrectionInfo correctionInfo) {
if (DEBUG) Log.v(TAG, "commitCorrection" + correctionInfo);
mTextView.beginBatchEdit();
mTextView.onCommitCorrection(correctionInfo);
mTextView.endBatchEdit();
return true;
}
#Override
public boolean performEditorAction(int actionCode) {
if (DEBUG) Log.v(TAG, "performEditorAction " + actionCode);
mTextView.onEditorAction(actionCode);
return true;
}
#Override
public boolean performContextMenuAction(int id) {
if (DEBUG) Log.v(TAG, "performContextMenuAction " + id);
mTextView.beginBatchEdit();
mTextView.onTextContextMenuItem(id);
mTextView.endBatchEdit();
return true;
}
#Override
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
if (mTextView != null) {
ExtractedText et = new ExtractedText();
if (mTextView.extractText(request, et)) {
if ((flags&GET_EXTRACTED_TEXT_MONITOR) != 0) {
// mTextView.setExtracting(request);
}
return et;
}
}
return null;
}
#Override
public boolean performPrivateCommand(String action, Bundle data) {
mTextView.onPrivateIMECommand(action, data);
return true;
}
#Override
public boolean commitText(CharSequence text, int newCursorPosition) {
if (mTextView == null) {
return super.commitText(text, newCursorPosition);
}
if (text instanceof Spanned) {
Spanned spanned = ((Spanned) text);
SuggestionSpan[] spans = spanned.getSpans(0, text.length(), SuggestionSpan.class);
// mIMM.registerSuggestionSpansForNotification(spans);
}
// mTextView.resetErrorChangedFlag();
boolean success = super.commitText(text, newCursorPosition);
// mTextView.hideErrorIfUnchanged();
return success;
}
#Override
public boolean requestCursorUpdates(int cursorUpdateMode) {
if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode);
// It is possible that any other bit is used as a valid flag in a future release.
// We should reject the entire request in such a case.
final int KNOWN_FLAGS_MASK = InputConnection.CURSOR_UPDATE_IMMEDIATE |
InputConnection.CURSOR_UPDATE_MONITOR;
final int unknownFlags = cursorUpdateMode & ~KNOWN_FLAGS_MASK;
if (unknownFlags != 0) {
if (DEBUG) {
Log.d(TAG, "Rejecting requestUpdateCursorAnchorInfo due to unknown flags." +
" cursorUpdateMode=" + cursorUpdateMode +
" unknownFlags=" + unknownFlags);
}
return false;
}
return false;
// if (mIMM == null) {
// // In this case, TYPE_CURSOR_ANCHOR_INFO is not handled.
// // TODO: Return some notification code rather than false to indicate method that
// // CursorAnchorInfo is temporarily unavailable.
// return false;
// }
// mIMM.setUpdateCursorAnchorInfoMode(cursorUpdateMode);
// if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0) {
// if (mTextView == null) {
// // In this case, FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE is silently ignored.
// // TODO: Return some notification code for the input method that indicates
// // FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE is ignored.
// } else if (mTextView.isInLayout()) {
// // In this case, the view hierarchy is currently undergoing a layout pass.
// // IMM#updateCursorAnchorInfo is supposed to be called soon after the layout
// // pass is finished.
// } else {
// // This will schedule a layout pass of the view tree, and the layout event
// // eventually triggers IMM#updateCursorAnchorInfo.
// mTextView.requestLayout();
// }
// }
// return true;
}
}
The class looks pretty bad because I commented out code that wouldn't build, presumably because it accesses internal Android APIs. That said, with a few caveats (cursor probably needs to be set manually when you switch to this input method, capitalization kind of carries-over between the two InputConnections), it works. All you have to do now is at some point set mOtherIC from my first paragraph to a new CustomInputConnection(yourTextfield) where yourTextfield is the textfield inside the keyboard.

Android 5.1 switch dual-sim radios on and off

Android 5.1 now has official support for Dual Sim phones, however there's not much currently available in the officially documented APIs. Does anybody know how, with a rooted phone, an app can switch either SIM1 or SIM 2 On and Off?
From the offical documentation mentioned the class SubscriptionManager,I just found something that could be switched:
DefaultVoice:
/** #hide */
public void setDefaultVoiceSubId(int subId) {
if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId);
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
iSub.setDefaultVoiceSubId(subId);
}
} catch (RemoteException ex) {
// ignore it
}
}
DefaultSms:
/** #hide */
public void setDefaultSmsSubId(int subId) {
if (VDBG) logd("setDefaultSmsSubId sub id = " + subId);
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
iSub.setDefaultSmsSubId(subId);
}
} catch (RemoteException ex) {
// ignore it
}
}
DefaultData:
/** #hide */
public void setDefaultDataSubId(int subId) {
if (VDBG) logd("setDataSubscription sub id = " + subId);
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
iSub.setDefaultDataSubId(subId);
}
} catch (RemoteException ex) {
// ignore it
}
}
But as you see,most of the methods of the class is #hide,that means it's not suitable to be public in the current version(Android 5.1.1/API Level 22).But you can also call them:
https://devmaze.wordpress.com/2011/01/19/using-com-android-internal-part-5-summary-and-example/
And also some information for you from this:
Android dual SIM card API

INSTALL_NON_MARKET_APPS alternative?

I need to check if the option "Install apps from unknown sources" is enabled or disabled. However, INSTALL_NON_MARKET_APPS was deprecated in API 17. Is there a new alternative to check this? This is the old way of checking:
boolean canInstallFromOtherSources = Settings.Secure.getInt(Settings.Secure.INSTALL_NON_MARKET_APPS) == 1;
Edit:
boolean unknownSource = false;
if (Build.VERSION.SDK_INT < 17) {
unknownSource = Settings.Secure.getInt(null, Settings.Secure.INSTALL_NON_MARKET_APPS, 0) == 1;
} else {
unknownSource = Settings.Global.getInt(null, Settings.Global.INSTALL_NON_MARKET_APPS, 0) == 1;
}
As the documentation for Settings.Secure.INSTALL_NON_MARKET_APPS points out, the replacement is Settings.Global.INSTALL_NON_MARKET_APPS.
Settings.Secure.INSTALL_NON_MARKET_APPS is deprecated in API 17 thus if you have minimalSDK set lower than 17, it is not directly reachable and reflection has to be used.
My solution:
public class BackwardCompatibility {
private static Class<?> settingsGlobal;
/**
* Returns Settings.Global class for reflective calls.
* Global is a nested class of the Settings, has to be done in a special way.
*
* #return
*/
public static Class<?> getSettingsGlobal(){
if (settingsGlobal!=null){
return settingsGlobal;
}
try {
Class<?> master = Class.forName("android.provider.Settings");
Class<?>[] classes = master.getClasses();
for(Class<?> cls : classes){
if (cls==null) {
continue;
}
if ("android.provider.Settings$Global".equals(cls.getName())){
settingsGlobal = cls;
return settingsGlobal;
}
}
return null;
} catch(Exception ex){
Log.e(TAG, "Reflective call not successfull", ex);
}
return null;
}
/**
* Determines whether installing Android apks from unknown sources is allowed.
*
* #param ctxt
* #return
*/
public static boolean isUnknownSourceInstallAllowed(Context ctxt){
try {
boolean unknownSource = false;
if (Build.VERSION.SDK_INT < 17) {
unknownSource = Settings.Secure.getInt(ctxt.getContentResolver(), Settings.Secure.INSTALL_NON_MARKET_APPS, 0) == 1;
} else {
// Has to use reflection since API 17 is not directly reachable.
// Original call would be:
// unknownSource = Settings.Global.getInt(ctxt.getContentResolver(), Settings.Global.INSTALL_NON_MARKET_APPS, 0) == 1;
//
Class<?> c = getSettingsGlobal();
Method m = c.getMethod("getInt", new Class[] { ContentResolver.class, String.class, int.class });
// Obtain constant value
Field f = c.getField("INSTALL_NON_MARKET_APPS");
final String constVal = (String) f.get(null);
unknownSource = Integer.valueOf(1).equals((Integer) m.invoke(null, ctxt.getContentResolver(), constVal, 0));
}
return unknownSource;
} catch(Exception e){
// Handle this as you like.
Log.w(TAG, "Cannot determine if installing from unknown sources is allowed", e);
}
return false;
}
}

How to check programmatically if data roaming is enabled/disabled?

I'm trying to check if the user has enabled/disabled data roaming. All I found so far is that you can check whether or not the user is currently IN roaming, using TelephonyManager.isNetworkRoaming() and NetworkInfo.isRoaming(), but they are not what I need.
Based on Nippey's answer, the actual piece of code that worked for me is:
public Boolean isDataRoamingEnabled(Context context) {
try {
// return true or false if data roaming is enabled or not
return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.DATA_ROAMING) == 1;
}
catch (SettingNotFoundException e) {
// return null if no such settings exist (device with no radio data ?)
return null;
}
}
You can request the state of the Roaming-Switch via
ContentResolver cr = ContentResolver(getCurrentContext());
Settings.Secure.getInt(cr, Settings.Secure.DATA_ROAMING);
See: http://developer.android.com/reference/android/provider/Settings.Secure.html#DATA_ROAMING
public static final Boolean isDataRoamingEnabled(final Context application_context)
{
try
{
if (VERSION.SDK_INT < 17)
{
return (Settings.System.getInt(application_context.getContentResolver(), Settings.Secure.DATA_ROAMING, 0) == 1);
}
return (Settings.Global.getInt(application_context.getContentResolver(), Settings.Global.DATA_ROAMING, 0) == 1);
}
catch (Exception exception)
{
return false;
}
}
Updated function to account for API deprecation. It is now replaced with:
http://developer.android.com/reference/android/provider/Settings.Global.html#DATA_ROAMING
public static boolean IsDataRoamingEnabled(Context context) {
try {
// return true or false if data roaming is enabled or not
return Settings.Global.getInt(context.getContentResolver(), Settings.Global.DATA_ROAMING) == 1;
}
catch (SettingNotFoundException e) {
return false;
}
}

Categories

Resources