The Problem
On Android versions < 4.1, the alpha value of the MenuItem is getting reset after an orientation change, BUT it remains disabled.
The code I'm using
DetailsFragment.java
public class DetailsFragment extends SherlockFragment {
private MenuItem miEmail;
...
#Override
public void onPrepareOptionsMenu(Menu menu) {
miEmail= menu.findItem(R.id.menu_email);
super.onPrepareOptionsMenu(menu);
}
private void populateDetails(final Detail oDetail) {
//disable email button if dealer doesn't have option
if(!oDetail.bShowSAM){
miEmail.setEnabled(false);
miEmail.getIcon().setAlpha(50);
}
...
}
}
MyManifest.xml
<activity
android:name=".activities.DetailsActivity"
android:uiOptions="splitActionBarWhenNarrow"
android:configChanges="keyboardHidden|screenSize|orientation">
</activity>
What I expect to happen
When the orientation changes, miEmail is still disabled and the alpha value is still at 50.
What is actually happening
When testing on older devices(2.3,4.0), the MenuItem is remaining disabled but the alpha value is getting reset to the default value. When testing with my devices that are >4.1, it is working as expected.
What I've tried
Googling the problem.......
I've tried to avoid using the android:configChanges="..." and handling the data through savedInstanceState, but I've learned you can't make the MenuItem serializable/parciable, thus not allowing me to pass it through outState bundle object.
I'm fairly new to Android development and I feel as though there is a trivial way of handling this MenuItem, but I cannot figure how else to handle it.
What do you think is the issue?
Any feedback will be greatly appreciated.
Dont set the icon alpha on your custom function, instead, set it on OnPrepareOptionsMenu (with a suitable conditional). You can pass a boolean on savedinstancestate saying whether it should be grayed or not.
In your populateDetails function, you would call invalidateOptionsMenu() to make android remake the action bar icons. Example:
private boolean buttonEnabled;
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem miEmail= menu.findItem(R.id.menu_email);
if (buttonEnabled) {
miEmail.setEnabled(true);
miEmail.getIcon().setAlpha(255);
}else{
miEmail.setEnabled(true);
miEmail.getIcon().setAlpha(50);
}
return super.onPrepareOptionsMenu(menu);
}
private void populateDetails(final Detail oDetail) {
//disable email button if dealer doesn't have option
if(!oDetail.bShowSAM){
buttonEnabled = false;
InvalidateOptionsMenu();
}
...
}
}
If you are using the support library for compatibility, use supportInvalidateOptionsMenu instead.
By the way, never use the orientation tag to "fix" the problem, the issue will still appear if you quit the app for a long time and then try to open it. (android pauses the activity initially and will stop it after a while)
Related
I want to disable copy/paste option of my Entry control in Xamarin forms application. I am using custom renderer for that. The current solution is working in all the other devices apart from Redmi Note 8. This is my renderer code.
class MyEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.CustomSelectionActionModeCallback = new Callback();
Control.CustomInsertionActionModeCallback = new Callback();
Console.WriteLine("CustomSelectionActionModeCallback");
Control.SetTextIsSelectable(false);
Control.LongClickable = false;
}
}
}
public class Callback : Java.Lang.Object, ActionMode.ICallback
{
public bool OnActionItemClicked(ActionMode mode, IMenuItem item)
{
Console.WriteLine("OnActionItemClicked");
return true;
}
public bool OnCreateActionMode(ActionMode mode, IMenu menu)
{
Console.WriteLine("OnCreateActionMode");
menu.Clear();
return false;
}
public void OnDestroyActionMode(ActionMode mode) {
Console.WriteLine("OnDestroyActionMode");
}
public bool OnPrepareActionMode(ActionMode mode, IMenu menu)
{
Console.WriteLine("OnPrepareActionMode");
menu.Clear();
menu.Close();
return true;
}
}
}
So long click is getting disabled in Redmi Note 8 but still there is blue color dot which appears. On click of that it still shows me copy/paste option. It is happening only in Redmi note 8. And in my code no other callback is getting hit other than OnDestroyActionMode and I'm not able to execute menu.Clear. In other devices that option is getting disabled by using this code
Control.SetTextIsSelectable(false);
This is how it is getting shown in Redmi Note 8 device.
I have referred these links because this issue is quite similar to mine but it didn't help.
Disable EditText context menu
EditText: Disable Paste/Replace menu pop-up on Text Selection Handler click event
As you can see in the image the paste option is getting shown in the device. I have no clue how to fix this bug any suggestions?
I have found two solutions for this. One is clearing the clipboard and other is setting the variation of input as visible password. Both these solutions serves my purpose. For clearing the clipboard you can use the following code in your renderer
var clipboardManager = (ClipboardManager)Forms.Context.GetSystemService(Context.ClipboardService);
clipboardManager.ClearPrimaryClip();
And for setting the variation of input as visible password you can use the following code
Control.InputType = Android.Text.InputTypes.ClassText | Android.Text.InputTypes.TextVariationVisiblePassword;
So these are the solutions which was useful for me.
After selecting item in ComboBox, then this selected item is not displayed in ComboBox - only Android device, on desktop is it ok.
Compare this two screenshots:
[On desktop when item "Option 2" is selected]
and
[On Android device when item "Option 2" is selected]
I am using JavaFXPorts 8.60.8.
Based on this question, and giving that on your bug report you mention you are using a Samsung device, there is a known issue in some Samsung devices where the touch event handling done in JavaFXPorts doesn't work as in the rest of Android devices.
While this is fix on JavaFXPorts, you can try the following workaround:
comboBox.setCellFactory(p -> new ListCell<String>() {
private String item;
{
setOnMousePressed(e -> comboBox.getSelectionModel().select(item));
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
this.item = item;
setText(item);
}
});
Note I've used a mouse pressed event handler instead of a mouse clicked event handler. Since I can't reproduce it, in my case the mouse click is consumed by the list selection event (as this works properly), but probably in your case you can use either pressed or clicked events.
Based on Josés answer I've implemented the following generic Helper function, which might help some of you:
public static <T> void removeSelectionBug(ComboBox<T> comboBox) {
comboBox.setCellFactory(p -> new ListCell<T>() {
private T item;
{
setOnMousePressed(e -> comboBox.getSelectionModel().select(item));
}
#Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
this.item = item;
if (item != null) {
setText(item.toString());
}
}
});
}
Btw: I've got this bug on all of my Mobiles(Samsung Note 3, Sony XPERIA Z3 Compact and Nexus 4)
Trying to call from static function? Its initialized because it calls from the onCreate of the activity. Wondering how crashlytics works.. does it require reference to some context that is somehow not present. Here is some code:
Calling from the activities menu override:
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch(item.getItemId())
{
case R.id.explore:
ListFragment.injectNewList(ListActivity.this, Stuff.getRandOffset());
break;
default:
break;
}
return true;
}
Calling function is a static function within a fragment:
public static void injectNewList(FragmentActivity activity, Integer offset)
{
ListFragment fragment = (ListFragment) activity.getSupportFragmentManager()
.findFragmentByTag(BaseFragmentActivity.LIST_FRAGMENT_TAG);
if(fragment != null)
{
fragment.nextOffset = offset;
FFData.getInstance().clearList();
fragment.mListAdapter.notifyDataSetInvalidated();
fragment.loadItems();
}
else
{
Crashlytics.log(Log.ERROR, "Log this error", "bad stuff happened!");
}
}
The activity and fragment are fully running when the menu button is clicked. I also see that the code is run in the debugger. Running on genymotion(will try actual device), SDK 19, Nexus5
Make sure Crashlytics is initialized first by calling Crashlytics.start(this);
Crashlytics.log will message will be visible in your dashboard, associated with crash (Meaning if no crash/exception happens, log will not be sent...Crashlytics is a crash tracking service, if you need to track custom messages there are other tools for that).
Since Ice-Cream-Sandwich there is a developer-option called "force GPU-rendering". If enabled it refuses to Display some large Drawables. Therefore I want to find out, if this option is enabled, to inform the User that he has to switch it off, if he wants to see that drawable.
Find a View that you know shouldn't be accelerated, which should be any View if you add
android:hardwareAccelerated="false"
to your <application> in Android Manifest, then in your code, call
view.isHardwareAccelerated();
If it returns true, the option is set as on. This has been confirmed to work on my Galaxy Nexus.
With the help of Kai I found this Hardware Acceleration topic on android-developers. Unfortunately We wanna stay compatible to 2.1 so I add my solution for anyone who has a similar problem. So inside an Activity:
public View contentView
public void onCreate(Bundle savedInstanceState){
contentView = findViewById(R.id.someId);
//initialize Views ...
setContentView(contentView);
//use a handler as easiest method to post a Runnable Delayed.
//we cannot check hardware-acceleration directly as it will return reasonable results after attached to Window.
Handler handler = new Handler();
handler.postDelayed(HardwareAccelerationRunnable(), 500);
}
public class HardwareAccelerationRunnable implements Runnable{
public void run(){
//now lets check for HardwareAcceleration since it is only avaliable since ICS.
// 14 = ICS_VERSION_CODE
if (android.os.Build.VERSION.SDK_INT >= 14){
try{
//use reflection to get that Method
Method isHardwareAccelerated = contentView.getClass().getMethod("isHardwareAccelerated", null);
Object o = isHardwareAccelerated.invoke(contentView, null);
if (null != o && o instanceof Boolean && (Boolean)o){
//ok we're shure that HardwareAcceleration is on.
//Now Try to switch it off:
Method setLayerType = contentView.getClass().getMethod("setLayerType", int.class, android.graphics.Paint.class);
setLayerType.invoke(contentView, 1, null);
}
} catch(Exception e){
e.printStackTrace();
}
}
}
}
}
I don't think that you can turn it off by adding
android:hardwareAccelerated="false"
If you trace the code into Window.setWindowManager(), you can see the following
public void setWindowManager(...) {
...
mHardwareAccelerated = hardwareAccelerated
|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
...
}
Where,
hardwareAccelerated: comes from android:hardwareAccelerated
PROPERTY_HARDWARE_UI property is set by the "Force GPU rendering" option.
You can see that if user manually check the "Force GPU rendering" option, mHardwareAccelerated variable will be assigned with a TRUE value no matter what android:hardwareAccelerated is.
I am using a webview to present some formatted stuff in my app. For some interaction (which are specific to certain dom elements) I use javascript and WebView.addJavascriptInterface(). Now, I want to recognize a long touch. Unfortunately, onLongTouch, in Android 2.3 the handles for text selection are displayed.
How can I turn off this text selection without setting the onTouchListener and return true? (Then, the interaction with the "website" doesn't work anymore.
This worked for me
mWebView.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
return true;
}
});
mWebView.setLongClickable(false);
I have not tested, if you don't want the vibration caused by the long click, you can try this:
mWebView.setHapticFeedbackEnabled(false);
Setting webkit css property -webkit-user-select to none would solve the problem.
Example CSS to disable selection:
* {
-webkit-user-select: none;
}
I figured it out!! This is how you can implement your own longtouchlistener. In the function longTouch you can make a call to your javascript interface.
var touching = null;
$('selector').each(function() {
this.addEventListener("touchstart", function(e) {
e.preventDefault();
touching = window.setTimeout(longTouch, 500, true);
}, false);
this.addEventListener("touchend", function(e) {
e.preventDefault();
window.clearTimeout(touching);
}, false);
});
function longTouch(e) {
// do something!
}
This works.
It appears that cut/paste via long press is turned off if you used
articleView.setWebChromeClient(new WebChromeClient(){...})
See https://bugzilla.wikimedia.org/show_bug.cgi?id=31484
So if you are using setChromeClient and you WANT to have long click to start copy/paste, the do the following:
webView.setWebChromeClient(new WebChromeClient(){
[.... other overrides....]
// #Override
// https://bugzilla.wikimedia.org/show_bug.cgi?id=31484
// If you DO NOT want to start selection by long click,
// the remove this function
// (All this is undocumented stuff...)
public void onSelectionStart(WebView view) {
// By default we cancel the selection again, thus disabling
// text selection unless the chrome client supports it.
// view.notifySelectDialogDismissed();
}
});
An alternative solution is to subclass WebView and Override performLongClick as bellow:
public class AdvanceWebView extends WebView {
//Add constructors...
#Override
public boolean performLongClick() {
return true;
}
}
It seems that the only option is to set onTouchListener and write your own code to detect long-click. Then return true if it's a long-click and false otherwise.
For kotlin i found the following to work:
webView.isLongClickable = false