1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package androidx.appcompat.view;
18
19import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
20
21import android.content.Context;
22import android.view.ActionMode;
23import android.view.Menu;
24import android.view.MenuInflater;
25import android.view.View;
26
27import androidx.annotation.RestrictTo;
28import androidx.appcompat.view.menu.MenuWrapperFactory;
29import androidx.collection.SimpleArrayMap;
30import androidx.core.internal.view.SupportMenu;
31import androidx.core.internal.view.SupportMenuItem;
32
33import java.util.ArrayList;
34
35/**
36 * Wraps a support {@link androidx.appcompat.view.ActionMode} as a framework
37 * {@link android.view.ActionMode}.
38 *
39 * @hide
40 */
41@RestrictTo(LIBRARY_GROUP)
42public class SupportActionModeWrapper extends ActionMode {
43
44    final Context mContext;
45    final androidx.appcompat.view.ActionMode mWrappedObject;
46
47    public SupportActionModeWrapper(Context context,
48            androidx.appcompat.view.ActionMode supportActionMode) {
49        mContext = context;
50        mWrappedObject = supportActionMode;
51    }
52
53    @Override
54    public Object getTag() {
55        return mWrappedObject.getTag();
56    }
57
58    @Override
59    public void setTag(Object tag) {
60        mWrappedObject.setTag(tag);
61    }
62
63    @Override
64    public void setTitle(CharSequence title) {
65        mWrappedObject.setTitle(title);
66    }
67
68    @Override
69    public void setSubtitle(CharSequence subtitle) {
70        mWrappedObject.setSubtitle(subtitle);
71    }
72
73    @Override
74    public void invalidate() {
75        mWrappedObject.invalidate();
76    }
77
78    @Override
79    public void finish() {
80        mWrappedObject.finish();
81    }
82
83    @Override
84    public Menu getMenu() {
85        return MenuWrapperFactory.wrapSupportMenu(mContext, (SupportMenu) mWrappedObject.getMenu());
86    }
87
88    @Override
89    public CharSequence getTitle() {
90        return mWrappedObject.getTitle();
91    }
92
93    @Override
94    public void setTitle(int resId) {
95        mWrappedObject.setTitle(resId);
96    }
97
98    @Override
99    public CharSequence getSubtitle() {
100        return mWrappedObject.getSubtitle();
101    }
102
103    @Override
104    public void setSubtitle(int resId) {
105        mWrappedObject.setSubtitle(resId);
106    }
107
108    @Override
109    public View getCustomView() {
110        return mWrappedObject.getCustomView();
111    }
112
113    @Override
114    public void setCustomView(View view) {
115        mWrappedObject.setCustomView(view);
116    }
117
118    @Override
119    public MenuInflater getMenuInflater() {
120        return mWrappedObject.getMenuInflater();
121    }
122
123    @Override
124    public boolean getTitleOptionalHint() {
125        return mWrappedObject.getTitleOptionalHint();
126    }
127
128    @Override
129    public void setTitleOptionalHint(boolean titleOptional) {
130        mWrappedObject.setTitleOptionalHint(titleOptional);
131    }
132
133    @Override
134    public boolean isTitleOptional() {
135        return mWrappedObject.isTitleOptional();
136    }
137
138    /**
139     * @hide
140     */
141    @RestrictTo(LIBRARY_GROUP)
142    public static class CallbackWrapper implements androidx.appcompat.view.ActionMode.Callback {
143        final Callback mWrappedCallback;
144        final Context mContext;
145
146        final ArrayList<SupportActionModeWrapper> mActionModes;
147        final SimpleArrayMap<Menu, Menu> mMenus;
148
149        public CallbackWrapper(Context context, Callback supportCallback) {
150            mContext = context;
151            mWrappedCallback = supportCallback;
152            mActionModes = new ArrayList<>();
153            mMenus = new SimpleArrayMap<>();
154        }
155
156        @Override
157        public boolean onCreateActionMode(androidx.appcompat.view.ActionMode mode, Menu menu) {
158            return mWrappedCallback.onCreateActionMode(getActionModeWrapper(mode),
159                    getMenuWrapper(menu));
160        }
161
162        @Override
163        public boolean onPrepareActionMode(androidx.appcompat.view.ActionMode mode, Menu menu) {
164            return mWrappedCallback.onPrepareActionMode(getActionModeWrapper(mode),
165                    getMenuWrapper(menu));
166        }
167
168        @Override
169        public boolean onActionItemClicked(androidx.appcompat.view.ActionMode mode,
170                android.view.MenuItem item) {
171            return mWrappedCallback.onActionItemClicked(getActionModeWrapper(mode),
172                    MenuWrapperFactory.wrapSupportMenuItem(mContext, (SupportMenuItem) item));
173        }
174
175        @Override
176        public void onDestroyActionMode(androidx.appcompat.view.ActionMode mode) {
177            mWrappedCallback.onDestroyActionMode(getActionModeWrapper(mode));
178        }
179
180        private Menu getMenuWrapper(Menu menu) {
181            Menu wrapper = mMenus.get(menu);
182            if (wrapper == null) {
183                wrapper = MenuWrapperFactory.wrapSupportMenu(mContext, (SupportMenu) menu);
184                mMenus.put(menu, wrapper);
185            }
186            return wrapper;
187        }
188
189        public ActionMode getActionModeWrapper(androidx.appcompat.view.ActionMode mode) {
190            // First see if we already have a wrapper for this mode
191            for (int i = 0, count = mActionModes.size(); i < count; i++) {
192                SupportActionModeWrapper wrapper = mActionModes.get(i);
193                if (wrapper != null && wrapper.mWrappedObject == mode) {
194                    // We've found a wrapper, return it
195                    return wrapper;
196                }
197            }
198
199            // If we reach here then we haven't seen this mode before. Create a new wrapper and
200            // add it to our collection
201            SupportActionModeWrapper wrapper = new SupportActionModeWrapper(mContext, mode);
202            mActionModes.add(wrapper);
203            return wrapper;
204        }
205    }
206}