[iOS] Add Tab Grid context menu actions

Bug: 1196953
Change-Id: Ib80ebf889af6cf1c84e0b3b9ac7deb433226ad0c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2841164
Commit-Queue: Mike Dougherty <michaeldo@chromium.org>
Auto-Submit: Mike Dougherty <michaeldo@chromium.org>
Reviewed-by: Robert Kaplow <rkaplow@chromium.org>
Reviewed-by: Gauthier Ambard <gambard@chromium.org>
Reviewed-by: Sebastien Lalancette <seblalancette@chromium.org>
Cr-Commit-Position: refs/heads/master@{#874990}
GitOrigin-RevId: f32268180be17731109719dccab8b57488b5b07f
diff --git a/chrome/app/strings/ios_strings.grd b/chrome/app/strings/ios_strings.grd
index d7db9dd..4bf3982 100644
--- a/chrome/app/strings/ios_strings.grd
+++ b/chrome/app/strings/ios_strings.grd
@@ -606,6 +606,12 @@
       <message name="IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST" desc="The iOS menu item for adding a link to the reading list.">
         Add to Reading List
       </message>
+      <message name="IDS_IOS_CONTENT_CONTEXT_ADDTOBOOKMARKS" desc="The iOS context menu item for adding the url of a tab to the bookmarks. [iOS only]">
+        Add to Bookmarks
+      </message>
+      <message name="IDS_IOS_CONTENT_CONTEXT_CLOSETAB" desc="The iOS context menu item for closing a tab. [iOS only]">
+        Close tab
+      </message>
       <message name="IDS_IOS_CONTENT_CONTEXT_COPY" desc="The iOS menu item for copying a link's URL into the pasteboard. Shorter than the desktop version [iOS only]">
         Copy Link URL
       </message>
diff --git a/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_CONTEXT_ADDTOBOOKMARKS.png.sha1 b/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_CONTEXT_ADDTOBOOKMARKS.png.sha1
new file mode 100644
index 0000000..b084a92
--- /dev/null
+++ b/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_CONTEXT_ADDTOBOOKMARKS.png.sha1
@@ -0,0 +1 @@
+359688ea1a4a8748e36fddeef3866be608ba33b0
\ No newline at end of file
diff --git a/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_CONTEXT_CLOSETAB.png.sha1 b/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_CONTEXT_CLOSETAB.png.sha1
new file mode 100644
index 0000000..b084a92
--- /dev/null
+++ b/chrome/app/strings/ios_strings_grd/IDS_IOS_CONTENT_CONTEXT_CLOSETAB.png.sha1
@@ -0,0 +1 @@
+359688ea1a4a8748e36fddeef3866be608ba33b0
\ No newline at end of file
diff --git a/chrome/browser/ui/menu/BUILD.gn b/chrome/browser/ui/menu/BUILD.gn
index c4b87f2..8b88757 100644
--- a/chrome/browser/ui/menu/BUILD.gn
+++ b/chrome/browser/ui/menu/BUILD.gn
@@ -12,6 +12,8 @@
   ]
   configs += [ "//build/config/compiler:enable_arc" ]
   deps = [
+    "resources:bookmark",
+    "resources:close",
     "resources:copy_link_url",
     "resources:delete",
     "resources:edit",
@@ -22,6 +24,7 @@
     "resources:open_in_incognito",
     "resources:open_in_new_tab",
     "resources:open_new_window",
+    "resources:read_later",
     "resources:remove",
     "resources:share",
     "//base",
@@ -51,6 +54,8 @@
   sources = [ "action_factory_unittest.mm" ]
   deps = [
     ":menu",
+    "resources:bookmark",
+    "resources:close",
     "resources:copy_link_url",
     "resources:delete",
     "resources:edit",
@@ -61,6 +66,7 @@
     "resources:open_in_incognito",
     "resources:open_in_new_tab",
     "resources:open_new_window",
+    "resources:read_later",
     "resources:remove",
     "resources:share",
     "//base",
diff --git a/chrome/browser/ui/menu/action_factory.h b/chrome/browser/ui/menu/action_factory.h
index 7ae3d32..8f5e31e 100644
--- a/chrome/browser/ui/menu/action_factory.h
+++ b/chrome/browser/ui/menu/action_factory.h
@@ -110,6 +110,15 @@
 // The action will invoke the |block| when executed.
 - (UIAction*)actionToOpenJavascriptWithBlock:(ProceduralBlock)block;
 
+// Creates a UIAction instance for adding to the reading list.
+- (UIAction*)actionToAddToReadingListWithBlock:(ProceduralBlock)block;
+
+// Creates a UIAction instance for adding to bookmarks.
+- (UIAction*)actionToBookmarkWithBlock:(ProceduralBlock)block;
+
+// Creates a UIAction instance for closing a tab.
+- (UIAction*)actionToCloseTabWithBlock:(ProceduralBlock)block;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_MENU_ACTION_FACTORY_H_
diff --git a/chrome/browser/ui/menu/action_factory.mm b/chrome/browser/ui/menu/action_factory.mm
index d9dcedf..107f310 100644
--- a/chrome/browser/ui/menu/action_factory.mm
+++ b/chrome/browser/ui/menu/action_factory.mm
@@ -241,4 +241,30 @@
                       block:block];
 }
 
+- (UIAction*)actionToAddToReadingListWithBlock:(ProceduralBlock)block {
+  return [self actionWithTitle:l10n_util::GetNSString(
+                                   IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST)
+                         image:[UIImage imageNamed:@"read_later"]
+                          type:MenuActionType::AddToReadingList
+                         block:block];
+}
+
+- (UIAction*)actionToBookmarkWithBlock:(ProceduralBlock)block {
+  return [self actionWithTitle:l10n_util::GetNSString(
+                                   IDS_IOS_CONTENT_CONTEXT_ADDTOBOOKMARKS)
+                         image:[UIImage imageNamed:@"bookmark"]
+                          type:MenuActionType::AddToBookmarks
+                         block:block];
+}
+
+- (UIAction*)actionToCloseTabWithBlock:(ProceduralBlock)block {
+  UIAction* action = [self
+      actionWithTitle:l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_CLOSETAB)
+                image:[UIImage imageNamed:@"close"]
+                 type:MenuActionType::CloseTab
+                block:block];
+  action.attributes = UIMenuElementAttributesDestructive;
+  return action;
+}
+
 @end
diff --git a/chrome/browser/ui/menu/action_factory_unittest.mm b/chrome/browser/ui/menu/action_factory_unittest.mm
index a8e6793..d8e2fa9 100644
--- a/chrome/browser/ui/menu/action_factory_unittest.mm
+++ b/chrome/browser/ui/menu/action_factory_unittest.mm
@@ -87,6 +87,44 @@
   }
 }
 
+// Tests that the bookmark action has the right title and image.
+TEST_F(ActionFactoryTest, BookmarkAction) {
+  if (@available(iOS 13.0, *)) {
+    ActionFactory* factory =
+        [[ActionFactory alloc] initWithBrowser:test_browser_.get()
+                                      scenario:kTestMenuScenario];
+
+    UIImage* expectedImage = [UIImage imageNamed:@"bookmark"];
+    NSString* expectedTitle =
+        l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_ADDTOBOOKMARKS);
+
+    UIAction* action = [factory actionToBookmarkWithBlock:^{
+    }];
+
+    EXPECT_TRUE([expectedTitle isEqualToString:action.title]);
+    EXPECT_EQ(expectedImage, action.image);
+  }
+}
+
+// Tests that the close action has the right title and image.
+TEST_F(ActionFactoryTest, CloseAction) {
+  if (@available(iOS 13.0, *)) {
+    ActionFactory* factory =
+        [[ActionFactory alloc] initWithBrowser:test_browser_.get()
+                                      scenario:kTestMenuScenario];
+
+    UIImage* expectedImage = [UIImage imageNamed:@"close"];
+    NSString* expectedTitle =
+        l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_CLOSETAB);
+
+    UIAction* action = [factory actionToCloseTabWithBlock:^{
+    }];
+
+    EXPECT_TRUE([expectedTitle isEqualToString:action.title]);
+    EXPECT_EQ(expectedImage, action.image);
+  }
+}
+
 // Tests that the copy action has the right title and image.
 TEST_F(ActionFactoryTest, CopyAction) {
   if (@available(iOS 13.0, *)) {
@@ -218,6 +256,25 @@
   }
 }
 
+// Tests that the read later action has the right title and image.
+TEST_F(ActionFactoryTest, ReadLaterAction) {
+  if (@available(iOS 13.0, *)) {
+    ActionFactory* factory =
+        [[ActionFactory alloc] initWithBrowser:test_browser_.get()
+                                      scenario:kTestMenuScenario];
+
+    UIImage* expectedImage = [UIImage imageNamed:@"read_later"];
+    NSString* expectedTitle =
+        l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST);
+
+    UIAction* action = [factory actionToAddToReadingListWithBlock:^{
+    }];
+
+    EXPECT_TRUE([expectedTitle isEqualToString:action.title]);
+    EXPECT_EQ(expectedImage, action.image);
+  }
+}
+
 // Tests that the remove action has the right title and image.
 TEST_F(ActionFactoryTest, RemoveAction) {
   if (@available(iOS 13.0, *)) {
diff --git a/chrome/browser/ui/menu/menu_action_type.h b/chrome/browser/ui/menu/menu_action_type.h
index 4554fcf..60fa598 100644
--- a/chrome/browser/ui/menu/menu_action_type.h
+++ b/chrome/browser/ui/menu/menu_action_type.h
@@ -24,7 +24,10 @@
   Unread = 12,
   ViewOffline = 13,
   OpenJavascript = 14,
-  kMaxValue = OpenJavascript
+  AddToReadingList = 15,
+  AddToBookmarks = 16,
+  CloseTab = 17,
+  kMaxValue = CloseTab
 };
 
 #endif  // IOS_CHROME_BROWSER_UI_MENU_MENU_ACTION_TYPE_H_
diff --git a/chrome/browser/ui/menu/menu_histograms.h b/chrome/browser/ui/menu/menu_histograms.h
index 9da9bc3..8bf62e9 100644
--- a/chrome/browser/ui/menu/menu_histograms.h
+++ b/chrome/browser/ui/menu/menu_histograms.h
@@ -19,7 +19,8 @@
   kContextMenuImage = 7,
   kContextMenuImageLink = 8,
   kContextMenuLink = 9,
-  kMaxValue = kContextMenuLink,
+  kTabGridEntry = 10,
+  kMaxValue = kTabGridEntry,
 };
 
 // Records a menu shown histogram metric for the |scenario|.
diff --git a/chrome/browser/ui/menu/menu_histograms.mm b/chrome/browser/ui/menu/menu_histograms.mm
index fc3a7c5..d6cbccd 100644
--- a/chrome/browser/ui/menu/menu_histograms.mm
+++ b/chrome/browser/ui/menu/menu_histograms.mm
@@ -29,6 +29,7 @@
     "Mobile.ContextMenu.HistoryEntry.Actions";
 const char kMostVisitedEntryActionsHistogram[] =
     "Mobile.ContextMenu.MostVisitedEntry.Actions";
+const char kTabGridActionsHistogram[] = "Mobile.ContextMenu.TabGrid.Actions";
 const char KContextMenuImageActionsHistogram[] =
     "Mobile.ContextMenu.WebImage.Actions";
 const char KContextMenuImageLinkActionsHistogram[] =
@@ -63,5 +64,7 @@
       return KContextMenuImageLinkActionsHistogram;
     case MenuScenario::kContextMenuLink:
       return KContextMenuLinkActionsHistogram;
+    case MenuScenario::kTabGridEntry:
+      return kTabGridActionsHistogram;
   }
 }
diff --git a/chrome/browser/ui/menu/resources/BUILD.gn b/chrome/browser/ui/menu/resources/BUILD.gn
index 4c8e025..f13283b 100644
--- a/chrome/browser/ui/menu/resources/BUILD.gn
+++ b/chrome/browser/ui/menu/resources/BUILD.gn
@@ -4,6 +4,22 @@
 
 import("//build/config/ios/asset_catalog.gni")
 
+imageset("bookmark") {
+  sources = [
+    "bookmark.imageset/Contents.json",
+    "bookmark.imageset/bookmark@2x.png",
+    "bookmark.imageset/bookmark@3x.png",
+  ]
+}
+
+imageset("close") {
+  sources = [
+    "close.imageset/Contents.json",
+    "close.imageset/close@2x.png",
+    "close.imageset/close@3x.png",
+  ]
+}
+
 imageset("copy_link_url") {
   sources = [
     "copy_link_url.imageset/Contents.json",
@@ -52,6 +68,14 @@
   ]
 }
 
+imageset("read_later") {
+  sources = [
+    "read_later.imageset/Contents.json",
+    "read_later.imageset/read_later@2x.png",
+    "read_later.imageset/read_later@3x.png",
+  ]
+}
+
 imageset("remove") {
   sources = [
     "remove.imageset/Contents.json",
diff --git a/chrome/browser/ui/menu/resources/bookmark.imageset/Contents.json b/chrome/browser/ui/menu/resources/bookmark.imageset/Contents.json
new file mode 100644
index 0000000..8c7ee47
--- /dev/null
+++ b/chrome/browser/ui/menu/resources/bookmark.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+  "images": [
+    {
+      "idiom": "universal",
+      "filename": "bookmark@2x.png",
+      "scale": "2x"
+    },
+    {
+      "idiom": "universal",
+      "filename": "bookmark@3x.png",
+      "scale": "3x"
+    }
+  ],
+  "info": {
+    "author": "xcode",
+    "version": 1
+  },
+  "properties": {
+    "template-rendering-intent": "template"
+  }
+}
diff --git a/chrome/browser/ui/menu/resources/bookmark.imageset/bookmark@2x.png b/chrome/browser/ui/menu/resources/bookmark.imageset/bookmark@2x.png
new file mode 100644
index 0000000..3b3a248
--- /dev/null
+++ b/chrome/browser/ui/menu/resources/bookmark.imageset/bookmark@2x.png
Binary files differ
diff --git a/chrome/browser/ui/menu/resources/bookmark.imageset/bookmark@3x.png b/chrome/browser/ui/menu/resources/bookmark.imageset/bookmark@3x.png
new file mode 100644
index 0000000..4284bac
--- /dev/null
+++ b/chrome/browser/ui/menu/resources/bookmark.imageset/bookmark@3x.png
Binary files differ
diff --git a/chrome/browser/ui/menu/resources/close.imageset/Contents.json b/chrome/browser/ui/menu/resources/close.imageset/Contents.json
new file mode 100644
index 0000000..2a18c8b
--- /dev/null
+++ b/chrome/browser/ui/menu/resources/close.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+  "images": [
+    {
+      "idiom": "universal",
+      "filename": "close@2x.png",
+      "scale": "2x"
+    },
+    {
+      "idiom": "universal",
+      "filename": "close@3x.png",
+      "scale": "3x"
+    }
+  ],
+  "info": {
+    "author": "xcode",
+    "version": 1
+  },
+  "properties": {
+    "template-rendering-intent": "template"
+  }
+}
diff --git a/chrome/browser/ui/menu/resources/close.imageset/close@2x.png b/chrome/browser/ui/menu/resources/close.imageset/close@2x.png
new file mode 100644
index 0000000..a9790d9
--- /dev/null
+++ b/chrome/browser/ui/menu/resources/close.imageset/close@2x.png
Binary files differ
diff --git a/chrome/browser/ui/menu/resources/close.imageset/close@3x.png b/chrome/browser/ui/menu/resources/close.imageset/close@3x.png
new file mode 100644
index 0000000..ab4acb6
--- /dev/null
+++ b/chrome/browser/ui/menu/resources/close.imageset/close@3x.png
Binary files differ
diff --git a/chrome/browser/ui/menu/resources/read_later.imageset/Contents.json b/chrome/browser/ui/menu/resources/read_later.imageset/Contents.json
new file mode 100644
index 0000000..a54f5f1
--- /dev/null
+++ b/chrome/browser/ui/menu/resources/read_later.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+  "images": [
+    {
+      "idiom": "universal",
+      "filename": "read_later@2x.png",
+      "scale": "2x"
+    },
+    {
+      "idiom": "universal",
+      "filename": "read_later@3x.png",
+      "scale": "3x"
+    }
+  ],
+  "info": {
+    "author": "xcode",
+    "version": 1
+  },
+  "properties": {
+    "template-rendering-intent": "template"
+  }
+}
diff --git a/chrome/browser/ui/menu/resources/read_later.imageset/read_later@2x.png b/chrome/browser/ui/menu/resources/read_later.imageset/read_later@2x.png
new file mode 100644
index 0000000..2cbd943
--- /dev/null
+++ b/chrome/browser/ui/menu/resources/read_later.imageset/read_later@2x.png
Binary files differ
diff --git a/chrome/browser/ui/menu/resources/read_later.imageset/read_later@3x.png b/chrome/browser/ui/menu/resources/read_later.imageset/read_later@3x.png
new file mode 100644
index 0000000..bba2a7e
--- /dev/null
+++ b/chrome/browser/ui/menu/resources/read_later.imageset/read_later@3x.png
Binary files differ