Dismiss the Contextual Action Bar When Nav. Drawer is Toggled - java

The official page for the Navigation Drawer design pattern states:
Sometimes the user will be in a state where a contextual action bar
(CAB) appears instead of the app’s action bar. This typically happens
when the user selects text or selects multiple items after a
press-and-hold gesture. While the CAB is visible, you should still
allow the user to open the navigation drawer using an edge swipe.
However, replace the CAB with the standard action bar while the navigation drawer is open. When the user dismisses the drawer,
re-display the CAB.
But after researching I can't seem to find a way to "dismiss" the Contextual Action Bar inside my
#Override
public void onDrawerOpened(View drawerView) {
// ... My Code ...
}
method.
In my case a CAB (with copy, paste, etc. options) may appear when a user selects text from an EditText in an Activity which itself displays a Nav. Drawer.
I've seen this question+answer but it doesn't quite fix my problem as it's related to a custom ActionMode. How can I "dismiss" the CAB - the one that shows up when a user selects text - whenever the navigation drawer is toggled?

It is possible. You have to grab a reference to the ActionMode when it is created, and the ActionMode.Callback in your Activity:
#Override
public void onActionModeStarted(ActionMode mode) {
super.onActionModeStarted(mode);
mActionMode = mode;
}
#Override
public void onActionModeFinished(ActionMode mode) {
super.onActionModeFinished(mode);
mActionMode = null;
}
#Override
public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
mActionModeCallback = callback;
return super.onWindowStartingActionMode(callback);
}
Then when your drawer opens/closes, finish the ActionMode or start a new ActionMode from the ActionMode.Callback:
#Override
public void onDrawerOpened(View drawerView) {
if (mActionMode != null) {
mActionMode.finish();
}
}
#Override
public void onDrawerClosed(View drawerView) {
if (mActionModeCallback != null) {
startActionMode(mActionModeCallback);
}
}

Related

Navigation Drawer has wierd behaviour

So my situation is that i've implemented navigation drawer correctly (so to speak, it displays properly and calls out method (in a weird way but it triggers)) but it acts weird and I don't know what else to do but to ask u peeps !
Once i've started binding methods to drawer's menu items (options) i've begun to notice weird behavior. Let me explain by words first :
Let this be dummy menu :
Ok so you see the order goes: home - history - favourite - logout
So far i've implemented history and favorite this is the behaviour i get :
If i call history it will open activity properly and display data
If i call favourite i will open HISTORY FIRST then FAVOURITE SECOND (i can see that because when i press back it closes favourite, opens history)
I've added a dummy activity as third option to menu (not displayed on pic) and i get the same behaviour but this time it opens History - Favourite - Dummy if i click on dummy activity.
One more thing before i post the code of how i implemented it.
Lets take 2 of mine activities and make real time example ( all in same ciclus).
1) From home page i try to use drawer and call out history/fav it works perfectly, i enter search i try to use drawer call out history/fav works perfeclty, i press back return to main activity (home) press drawer to open history/favourite and puuf it's not working anymore... any idea if it's connected or just an separate problem to solve?
Implementation:
final NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
// set item as selected to persist highlight
menuItem.setChecked(true);
// close drawer when item is tapped
switch (menuItem.getItemId()) {
case R.id.nav_home: {
if (checkInternetConnection(getApplicationContext())) {
Log.i(LOG_TAG, "PROVJERA NETA POVEZAN");
start_loader();
} else {
mEmptyStateTextView.setText("Cannot connect to network, please check your network status and try again.");
// Clear the adapter of previous earthquake data
}
}
case R.id.nav_history: {
pozoviHistory(null);
}
case R.id.nav_favourite: {
pozoviFavorites();
}
}
mDrawerLayout.closeDrawers();
// Add code here to update the UI based on the item selected
// For example, swap UI fragments here
return true;
}
}
);
mDrawerLayout.addDrawerListener(
new DrawerLayout.DrawerListener() {
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
// Respond when the drawer's position changes
}
#Override
public void onDrawerOpened(View drawerView) {
// Respond when the drawer is opened
}
#Override
public void onDrawerClosed(View drawerView) {
// Respond when the drawer is closed
navigationView.getMenu().getItem(0).setChecked(true);
}
#Override
public void onDrawerStateChanged(int newState) {
// Respond when the drawer motion state changes
}
}
);
****** EDIT ********
Okay so from the answer below adding the break; to each case resolved issue of opening everything. I've managed to find more symptoms causing drawer to act dumb.
So the action i'm doing that's causing drawer to act dumb is :
- I've got inside activity a thread which makes http request and starts media player.
- Once the thread is finished through the listener i've added i begin reproduction of media player
- Once it initializes i inflate my layout with some layout that represents media player( could this be the issue of making drawer dumbs ? )
- Also slide right-to-left (for closing) is not working but clicking outside drawer (on activity layout) closes it normally
This is how i inflate :
DrawerLayout myLayout = (DrawerLayout) findViewById(R.id.cili_test);
View itemInfo1 = getLayoutInflater().inflate(R.layout.player2, myLayout, true);
You need to add break; in your switch case
Like this:
switch (menuItem.getItemId()) {
case R.id.nav_home: {
if (checkInternetConnection(getApplicationContext())) {
Log.i(LOG_TAG, "PROVJERA NETA POVEZAN");
start_loader();
} else {
mEmptyStateTextView.setText("Cannot connect to network, please check your network status and try again.");
// Clear the adapter of previous earthquake data
}
break;
}
case R.id.nav_history: {
pozoviHistory(null);
break;
}
case R.id.nav_favourite: {
pozoviFavorites();
break;
}
}

Check if popup menu become inactive / check if popup menu is visible

Hello I am making a small app where i have a list and different popup menus.
I am shading the selected item when the popup menu is triggered.
Is there a way to check if the popup menu that has been active is now not active any more?
For instance I have the popup menu open and i press somewhere else on the screen. The popup menu Disappears. Is there a listener to capture that?
popupMenu2 = new PopupMenu(getContext(), v);
popupMenu2.getMenuInflater().inflate(R.menu.popup_unknown_number,
popupMenu2.getMenu());
popupMenu2.setOnMenuItemClickListener(new
PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.delete_unknown) deleteVM(v,model);
return true;
}
});
popupMenu2.show();
Shading is done by
v.setSelected(true);
Found he answer. There is a dismiss listener for PopupMenus
popupMenu.setOnDismissListener(new PopupMenu.OnDismissListener(){
#Override
public void onDismiss(PopupMenu popupMenu) {
// TODO Auto-generated method stub
}
});

Make the extra action bar icon go away

I've managed to work around an issue in which an extra icon appears in the action bar after a fragment transaction, but it was a clumsy solution and I wonder if there is a better way to solve it.
I have a fragment class hierarchy in which ContentFragment is an abstract fragment which occupies the whole screen (except for the action bar) and its subclasses contribute with additional action bar icons (by means of their respective onCreateOptionsMenu() and onOptionsItemSelected() methods). E.g. ContentFragmentA contributes with icon A, ContentFragmentB with icon B, ContentFragmentB may or may not be a child class of ContentFragmentA (if it is, then the action bar will contain both icon A and icon B side by side), and so on.
Initially (after the user has just logged in) the screen contains only ContentFragmentA and the action bar has icon A. As the user navigates through the app other content fragments (or more precisely fragment transactions) are added to the back stack and icons are correspondingly added or removed from the action bar.
It all behaves nicely until the user decides to log out which prompts the app to clear the whole back stack (bringing ContentFragmentA back after the oldest transaction is rolled back) and immediately add a LoginContentFragment, which contributes with a New Profile icon to the action bar. However at this moment icon A is also being shown beside the New Profile icon and I don't want it to be shown; that is the issue I'm facing. It should go away when the user logs out.
I solved the issue by clearing the back stack as usual and then including an extra transaction which replaces the ContentFragmentA with a blank, icon-less content fragment with setHasOptionsMenu(false), so icon A will be gone when the blank fragment is replaced with the Login fragment. But I find this clumsy and think there might be a better way.
I have tried out calling Menu.clear() in the ContentFragment superclass and Activity.supportInvalidateOptionsMenu() in the fragment replacement step but neither seems to work. Menu.clear() in particular will just make all the icons go away leaving none in the action bar.
Does anyone know an alternative?
Relevant code:
ContentFragment.java:
public abstract class ContentFragment extends Fragment {
public static interface Callbacks {
public abstract void setCurrentContentFragment(ContentFragment contentFragment);
}
protected Callbacks mCallbacks;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onStart() {
super.onStart();
mCallbacks = (Callbacks)getActivity();
mCallbacks.setCurrentContentFragment(this);
}
#Override
public void onStop() {
super.onStop();
mCallbacks = null;
}
public boolean handleBackPressed() {
return false;
}
}
ContentFragmentA.java:
public abstract class ContentFragmentA extends ContentFragment {
protected abstract void handleIconATouched();
...
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (menu.findItem(R.id.icon_a) == null) {
inflater.inflate(R.menu.icon_a, menu);
}
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.icon_a) {
handleIconATouched();
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
}
BlankFragment.java:
public class BlankFragment extends LoggedInContentFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(false);
}
}
In MainActivity.java:
...
private void addContentFragmentNotAddingTransactionToBackStackIfCurrentFragment(ContentFragment fragment, boolean clearBackStack) {
// mCurrentContentFragment changes as the back stack is cleared, thus addToBackStack is calculated before the clearBackStack() step.
boolean addToBackStack = (false == clearBackStack && (mCurrentContentFragment != null && fragment.getClass() != mCurrentContentFragment.getClass()));
if (clearBackStack) {
clearBackStack();
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (addToBackStack) {
ft.addToBackStack(null);
}
ft.replace(R.id.container, fragment);
ft.commit();
getSupportFragmentManager().executePendingTransactions();
}
public void clearBackStack() {
while (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStackImmediate();
}
// This is the step I would like to avoid
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.container, new BlankFragment());
ft.commit();
getSupportFragmentManager().executePendingTransactions();
}
...
I solved the issue. It was a problem with the fragment transaction back stack. I was mixing transactions which were added to the back stack with ones that weren't, and these were causing the back stack popping to work in an unexpected way and prevent fragments from being correctly removed so they were adding extra icons to the action bar. The issue is explained in this SO question. The solution I adopted is this one.

Android app for Wifi automation

I want to develop an android app that triggers Wifi..
When we open the app, if our Wifi is on, it will toast Connected Message Else, a button having a text connect will be displayed and
when you click that button, button text will change to connected and your Wifi is turned on.
I have done this .. but
my sir asked me to introduce such change that once we press button it changes from connect to connected and Wifi is on..
Now, if we manually turn off the Wifi in our setting and then we open our paused app, then the button will show connect option again.
I want to introduce automation in my app. My sir gave me hint that there is some helper class in android which keep on calling the method or some event handler that handles the event that occurs outside the app, but I still have no idea how to do that.
Please help me, thanks!
Here is the java code of my app:
public class MainActivity extends ActionBarActivity implements OnClickListener {
WifiManager wf;
static Button buttn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttn = (Button) findViewById(R.id.button);
buttn.setOnClickListener(this);
wf = (WifiManager) getSystemService(Context.WIFI_SERVICE);
}
public void onClick(View v) {
if (v == buttn) {
wf.setWifiEnabled(true);
buttn.setText("connected");
Toast.makeText(this, "Wifi Connected", Toast.LENGTH_LONG).show();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
// noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
I'd take a look at an Activity's Life cycle here
I believe you'll be interested in the "onResume" and able to detect if WiFi is still connected there.

Action Bar Home Button not functional with nested PreferenceScreen

I found a workaround to actually enable the ActionBar home button on the nested PreferenceScreen... however it doesn't call OnOptionsItemSelected in my PreferenceActivity. Anyone know a way to actually use the home button on a nested PreferenceScreen?
Modification of post 35 here:
http://code.google.com/p/android/issues/detail?id=4611
#Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)
{
super.onPreferenceTreeClick(preferenceScreen, preference);
if (preference!=null)
if (preference instanceof PreferenceScreen)
if (((PreferenceScreen)preference).getDialog()!=null)
((PreferenceScreen)preference).getDialog().getActionBar().setHomeButtonEnabled(true);
return false;
}
I had this problem recently and this is how I solved it. Firstly to access the PreferenceScreen I use the exact same method you mentioned above.
#Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
super.onPreferenceTreeClick(preferenceScreen, preference);
// If the user has clicked on a preference screen, set up the action bar
if (preference instanceof PreferenceScreen) {
initializeActionBar((PreferenceScreen) preference);
}
return false;
}
From here I looked into what a PreferenceScreen is, and I was saddened to find out it is just wrapper of a Dialog. Moving forward, I then set the actionbar display options and attempt find the home button area. This unfortunately wasn't too easy to get, but with the help of the hierarchy viewer I managed to gain access by finding the home icon and then its parent views. Once we have access to the containing LinearLayout, we can attach an onClickListener where we dismiss the PreferenceScreen's dialog, which calls PreferenceScreen's onDismissListener and returns us to the previous screen.
/** Sets up the action bar for an {#link PreferenceScreen} */
public static void initializeActionBar(PreferenceScreen preferenceScreen) {
final Dialog dialog = preferenceScreen.getDialog();
if (dialog != null) {
// Inialize the action bar
dialog.getActionBar().setDisplayHomeAsUpEnabled(true);
// Apply custom home button area click listener to close the PreferenceScreen because PreferenceScreens are dialogs which swallow
// events instead of passing to the activity
// Related Issue: https://code.google.com/p/android/issues/detail?id=4611
View homeBtn = dialog.findViewById(android.R.id.home);
if (homeBtn != null) {
OnClickListener dismissDialogClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
};
// Prepare yourselves for some hacky programming
ViewParent homeBtnContainer = homeBtn.getParent();
// The home button is an ImageView inside a FrameLayout
if (homeBtnContainer instanceof FrameLayout) {
ViewGroup containerParent = (ViewGroup) homeBtnContainer.getParent();
if (containerParent instanceof LinearLayout) {
// This view also contains the title text, set the whole view as clickable
((LinearLayout) containerParent).setOnClickListener(dismissDialogClickListener);
} else {
// Just set it on the home button
((FrameLayout) homeBtnContainer).setOnClickListener(dismissDialogClickListener);
}
} else {
// The 'If all else fails' default case
homeBtn.setOnClickListener(dismissDialogClickListener);
}
}
}
}

Categories