I've been developing an app in a Marshmallow 6.0 phone. Today, I ran it in a Nougat 7.0 phone and everything was ok. Changed one line of xml code ('selectableItemBackground' to 'selectableItemBackgroundBorderless' in a LinearLayout) and got an NPE on an unrelated MenuItem ("Attempt to invoke interface method 'android.view.MenuItem android.view.MenuItem.setIcon(int)' on a null object reference") here:
public void updateSpeakerIcon() {
if (mIsSpeakerOn) {
mSpeakerIcon.setIcon(R.drawable.speaker);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
} else {
mSpeakerIcon.setIcon(R.drawable.earphone);
setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
}
}
I'm using a ViewPager; this method is declared in the activity that contains it; the fragments call this method in their onResume callback.
mSpeakerIcon is 'found' in the onCreateOptionsMenu callback, in the same activity:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.qmenu, menu);
mSpeakerIcon = menu.findItem(R.id.toggle_speaker);
return true;
}
I've changed the one line back to what it was but, of course, it did not fix the problem. Ran the app once again in the 6.0 device and there's no error.
Any ideas? Thanks in advance!
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.
I have a working searchable Activity that queries a remote database upon submitting input in the ActionBar's android.support.v7.widget.SearchView (entering "Go" on the soft keyboard). This works fine, but I would ultimately like to query the database each time the SearchView's text changes via adding or removing a character. My initialization code of the SearchView is below.
SearchFragment.java (child fragment of the searchable Activity mentioned above)
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_search, menu);
// Get the searchable.xml data about the search configuration
final SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
SearchableInfo searchInfo = searchManager.getSearchableInfo(getActivity().getComponentName());
// Associate searchable configuration with the SearchView
mSearchView = (SearchView) menu.findItem(R.id.menu_item_search).getActionView();
mSearchView.setSearchableInfo(searchInfo);
mSearchView.requestFocus();
mSearchView.onActionViewExpanded();
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
mSearchListAdapter.clear();
return false;
}
#Override
public boolean onQueryTextChange(String query) {
mSearchListAdapter.clear();
// Execute search ...
return false;
}
});
}
I imagine the work needs to be done within the onQueryTextChange(String query) method above, but I'm not sure what needs to be called. I thought of invoking the SearchManager's startSearch instance method, but that doesn't appear to be best practice. Does anyone have any experience with type-to-search and would be willing to share an efficient solution?
UPDATE:
MainActivity.java (the searchable Activity)
#Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
// Handle the search for a particular musical object
final SearchFragment searchFragment = (SearchFragment) getFragmentManager().findFragmentByTag(SearchFragment.TAG);
String query = intent.getStringExtra(SearchManager.QUERY);
mWebService.searchTracks(query, new Callback<Pager>() {
#Override
public void success(Pager results, Response response) {
Log.d(TAG, "Search response received.");
searchFragment.updateItems(results);
}
#Override
public void failure(RetrofitError retrofitError) {
Log.e(TAG, "Search response failed: " + retrofitError.toString());
}
});
The above search interface design is what's recommended by the Android team at Google.
So far, the only solution that I have come across after reading through several pages of documentation is simply sending an intent with the Intent.ACTION_SEARCH action and the current query from the SearchView to start the searchable Activity whenever the SearchView's text changes. Keep in mind that this probably isn't the best practice in terms of the SearchManager design, but it works. I'll revisit this approach at a later date and report back here if I come across anything new.
#Override
public boolean onQueryTextChange(String query) {
mSearchListAdapter.clear();
if (!query.isEmpty()) {
Intent searchIntent = new Intent(getActivity(), MainActivity.class);
searchIntent.setAction(Intent.ACTION_SEARCH);
searchIntent.putExtra(SearchManager.QUERY, query);
startActivity(searchIntent);
}
return false;
}
A TextWatcher should be what you are looking for. It also offers for executing code before or after the text has changed.
http://developer.android.com/reference/android/text/TextWatcher.html
When an object of a type is attached to an Editable, its methods will be called when the text is changed.
This is the perfect solution for the issue you are looking for.
See this this will help you...
Android Action Bar SearchView as Autocomplete?
In case you're still looking for a better solution:
I just found this answer to a similar question, which uses
searchView.setOnQueryTextListener(this);
which is exactly what you want.
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).
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)
My goal is to support a functionality that mute phone (possibly with vibrations enabled/disabled), so when a call or sms is received it won't make noise
unmute phone but prompt for "password for unmute".
And this remains valid for any other application, that it ask for password entry before unmute...
How can I do this? What permissions are required in AndroidManifest?
Previously on Stackoverflow, Android mute/unmute phone.
Those answers discuss both permissions and the coding. Also, tasker can handle everything you're looking to do.
And here's a link to a tutorial.
The code below runs fine in the emulator. When you run it, you can see the mute goes on in the notification area. In addition to the code, I had to add the (uses) permission for android.permission.MODIFY_AUDIO_SETTINGS.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
AudioManager audio = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
audio.setRingerMode(AudioManager.RINGER_MODE_SILENT);
return true;
}