Optimizing option menu invalidation

Bug: 3296198
Change-Id: Ic8ed6b474a5aceccde620859fc2f93222637da27
diff --git a/src/com/android/contacts/activities/ContactBrowserActivity.java b/src/com/android/contacts/activities/ContactBrowserActivity.java
index c8d8a5f..5379209 100644
--- a/src/com/android/contacts/activities/ContactBrowserActivity.java
+++ b/src/com/android/contacts/activities/ContactBrowserActivity.java
@@ -126,6 +126,10 @@
     private ProviderStatusLoader mProviderStatusLoader;
     private int mProviderStatus = -1;
 
+    private boolean mOptionsMenuContactsAvailable;
+    private boolean mOptionsMenuGroupActionsEnabled;
+    private boolean mOptionsMenuCustomFilterChangeable;
+
     public ContactBrowserActivity() {
         mIntentResolver = new ContactsIntentResolver(this);
         mContactListFilterController = new ContactListFilterController(this);
@@ -732,20 +736,69 @@
     }
 
     @Override
+    public void invalidateOptionsMenu() {
+        if (isOptionsMenuChanged()) {
+            super.invalidateOptionsMenu();
+        }
+    }
+
+    public boolean isOptionsMenuChanged() {
+        if (mOptionsMenuContactsAvailable != areContactsAvailable()) {
+            return true;
+        }
+
+        if (mOptionsMenuGroupActionsEnabled != areGroupActionsEnabled()) {
+            return true;
+        }
+
+        if (mOptionsMenuCustomFilterChangeable != isCustomFilterChangeable()) {
+            return true;
+        }
+
+        if (mListFragment != null && mListFragment.isOptionsMenuChanged()) {
+            return true;
+        }
+
+        if (mDetailFragment != null && mDetailFragment.isOptionsMenuChanged()) {
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
-        if (!areContactsAvailable()) {
+        mOptionsMenuContactsAvailable = areContactsAvailable();
+        if (!mOptionsMenuContactsAvailable) {
             return false;
         }
 
         MenuItem settings = menu.findItem(R.id.menu_settings);
         settings.setVisible(!ContactsPreferenceActivity.isEmpty(this));
 
+        mOptionsMenuCustomFilterChangeable = isCustomFilterChangeable();
+
         MenuItem displayGroups = menu.findItem(R.id.menu_display_groups);
         if (displayGroups != null) {
-            displayGroups.setVisible(
-                    mRequest.getActionCode() == ContactsRequest.ACTION_DEFAULT);
+            displayGroups.setVisible(mOptionsMenuCustomFilterChangeable);
         }
 
+        mOptionsMenuGroupActionsEnabled = areGroupActionsEnabled();
+
+        MenuItem renameGroup = menu.findItem(R.id.menu_rename_group);
+        if (renameGroup != null) {
+            renameGroup.setVisible(mOptionsMenuGroupActionsEnabled);
+        }
+
+        MenuItem deleteGroup = menu.findItem(R.id.menu_delete_group);
+        if (deleteGroup != null) {
+            deleteGroup.setVisible(mOptionsMenuGroupActionsEnabled);
+        }
+
+        return true;
+    }
+
+    private boolean areGroupActionsEnabled() {
         boolean groupActionsEnabled = false;
         if (mListFragment != null) {
             ContactListFilter filter = mListFragment.getFilter();
@@ -755,18 +808,11 @@
                 groupActionsEnabled = true;
             }
         }
+        return groupActionsEnabled;
+    }
 
-        MenuItem renameGroup = menu.findItem(R.id.menu_rename_group);
-        if (renameGroup != null) {
-            renameGroup.setVisible(groupActionsEnabled);
-        }
-
-        MenuItem deleteGroup = menu.findItem(R.id.menu_delete_group);
-        if (deleteGroup != null) {
-            deleteGroup.setVisible(groupActionsEnabled);
-        }
-
-        return true;
+    public boolean isCustomFilterChangeable() {
+        return mRequest.getActionCode() == ContactsRequest.ACTION_DEFAULT;
     }
 
     @Override
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 8d45ec8..ccbdb7c 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -53,7 +53,6 @@
 import android.content.Intent;
 import android.content.Loader;
 import android.content.res.Resources;
-import android.database.Cursor;
 import android.graphics.drawable.Drawable;
 import android.net.ParseException;
 import android.net.Uri;
@@ -91,7 +90,6 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.view.View.OnCreateContextMenuListener;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
@@ -135,6 +133,10 @@
     private String mDefaultCountryIso;
     private boolean mContactDataDisplayed;
 
+    private boolean mOptionsMenuOptions;
+    private boolean mOptionsMenuEditable;
+    private boolean mOptionsMenuShareable;
+
     /**
      * Device capability: Set during buildEntries and used in the long-press context menu
      */
@@ -968,25 +970,44 @@
         inflater.inflate(R.menu.view, menu);
     }
 
+    public boolean isOptionsMenuChanged() {
+        return mOptionsMenuOptions != isContactOptionsChangeEnabled()
+                || mOptionsMenuEditable != isContactEditable()
+                || mOptionsMenuShareable != isContactShareable();
+    }
+
     @Override
     public void onPrepareOptionsMenu(Menu menu) {
-        boolean isEmpty = mContactData == null;
-        boolean isDirectoryEntry = !isEmpty && mContactData.isDirectoryEntry();
+        mOptionsMenuOptions = isContactOptionsChangeEnabled();
+        mOptionsMenuEditable = isContactEditable();
+        mOptionsMenuShareable = isContactShareable();
 
         // Options only shows telephony-related settings (ringtone, send to voicemail).
         // ==> Hide if we don't have a telephone
         final MenuItem optionsMenu = menu.findItem(R.id.menu_options);
-        final boolean deviceHasPhone = PhoneCapabilityTester.isPhone(mContext);
-        optionsMenu.setVisible(!isEmpty && !isDirectoryEntry && deviceHasPhone);
+        optionsMenu.setVisible(mOptionsMenuOptions);
 
         final MenuItem editMenu = menu.findItem(R.id.menu_edit);
-        editMenu.setVisible(!isEmpty && !isDirectoryEntry);
+        editMenu.setVisible(mOptionsMenuEditable);
 
         final MenuItem deleteMenu = menu.findItem(R.id.menu_delete);
-        deleteMenu.setVisible(!isEmpty && !isDirectoryEntry);
+        deleteMenu.setVisible(mOptionsMenuEditable);
 
         final MenuItem shareMenu = menu.findItem(R.id.menu_share);
-        shareMenu.setVisible(!isEmpty && !isDirectoryEntry && !mAllRestricted);
+        shareMenu.setVisible(mOptionsMenuShareable);
+    }
+
+    public boolean isContactOptionsChangeEnabled() {
+        return mContactData != null && !mContactData.isDirectoryEntry()
+                && PhoneCapabilityTester.isPhone(mContext);
+    }
+
+    public boolean isContactEditable() {
+        return mContactData != null && !mContactData.isDirectoryEntry();
+    }
+
+    public boolean isContactShareable() {
+        return mContactData != null && !mContactData.isDirectoryEntry() && !mAllRestricted;
     }
 
     @Override
diff --git a/src/com/android/contacts/list/ContactBrowseListFragment.java b/src/com/android/contacts/list/ContactBrowseListFragment.java
index e0626e0..10c497d 100644
--- a/src/com/android/contacts/list/ContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/ContactBrowseListFragment.java
@@ -363,6 +363,7 @@
         refreshSelectedContactUri();
     }
 
+    @Override
     public void onLoaderReset(Loader<Cursor> loader) {
     }
 
@@ -575,4 +576,9 @@
             return mPersistentSelectionPrefix + "-" + mFilter.getId();
         }
     }
+
+    public boolean isOptionsMenuChanged() {
+        // This fragment does not have an option menu of its own
+        return false;
+    }
 }