cid#1607171 Data race condition
[LibreOffice.git] / android / source / src / java / org / libreoffice / FontController.java
blob211b9d6c8b560cd5161279674297fe51d09ef807
1 package org.libreoffice;
3 import android.graphics.Color;
4 import android.graphics.Rect;
5 import com.google.android.material.bottomsheet.BottomSheetBehavior;
6 import androidx.recyclerview.widget.GridLayoutManager;
7 import androidx.recyclerview.widget.RecyclerView;
8 import android.view.View;
9 import android.widget.AdapterView;
10 import android.widget.ArrayAdapter;
11 import android.widget.Button;
12 import android.widget.ImageButton;
13 import android.widget.LinearLayout;
14 import android.widget.RelativeLayout;
15 import android.widget.Spinner;
17 import org.json.JSONArray;
18 import org.json.JSONException;
19 import org.json.JSONObject;
21 import java.util.ArrayList;
23 public class FontController implements AdapterView.OnItemSelectedListener {
25 /** -1 as value in ".uno:Color" et al. means "automatic color"/no color set. */
26 private static final int COLOR_AUTO = -1;
28 private boolean mFontNameSpinnerSet = false;
29 private boolean mFontSizeSpinnerSet = false;
30 private final LibreOfficeMainActivity mActivity;
31 private final ArrayList<String> mFontList = new ArrayList<>();
32 private final ArrayList<String> mFontSizes = new ArrayList<>();
34 private String mCurrentFontSelected = null;
35 private String mCurrentFontSizeSelected = null;
37 public FontController(LibreOfficeMainActivity activity) {
38 mActivity = activity;
40 private BottomSheetBehavior colorPickerBehavior;
41 private BottomSheetBehavior backColorPickerBehavior;
42 private BottomSheetBehavior toolBarBottomBehavior;
43 private ColorPickerAdapter colorPickerAdapter;
44 private ColorPickerAdapter backColorPickerAdapter;
46 final ColorPaletteListener colorPaletteListener = new ColorPaletteListener() {
47 @Override
48 public void applyColor(int color) {
49 sendFontColorChange(color, false);
52 @Override
53 public void updateColorPickerPosition(int color) {
54 if (colorPickerAdapter == null) {
55 return;
57 if (color == COLOR_AUTO) {
58 colorPickerAdapter.unselectColors();
59 changeFontColorBoxColor(Color.TRANSPARENT);
60 return;
62 final int colorWithAlpha = color | 0xFF000000;
63 colorPickerAdapter.findSelectedTextColor(colorWithAlpha);
64 changeFontColorBoxColor(colorWithAlpha);
68 final ColorPaletteListener backColorPaletteListener = new ColorPaletteListener() {
69 @Override
70 public void applyColor(int color) {
71 sendFontBackColorChange(color, false);
74 @Override
75 public void updateColorPickerPosition(int color) {
76 if (backColorPickerAdapter == null) {
77 return;
79 if (color == COLOR_AUTO) {
80 backColorPickerAdapter.unselectColors();
81 changeFontBackColorBoxColor(Color.TRANSPARENT);
82 return;
84 final int colorWithAlpha = color | 0xFF000000;
85 backColorPickerAdapter.findSelectedTextColor(colorWithAlpha);
86 changeFontBackColorBoxColor(colorWithAlpha);
90 private void changeFontColorBoxColor(final int color){
91 final ImageButton fontColorPickerButton = mActivity.findViewById(R.id.font_color_picker_button);
93 LOKitShell.getMainHandler().post(new Runnable() {
94 @Override
95 public void run() {
96 fontColorPickerButton.setBackgroundColor(color);
98 });
101 private void changeFontBackColorBoxColor(final int color){
102 final ImageButton fontBackColorPickerButton = mActivity.findViewById(R.id.font_back_color_picker_button);
104 LOKitShell.getMainHandler().post(new Runnable() {
105 @Override
106 public void run() {
107 fontBackColorPickerButton.setBackgroundColor(color);
112 private void sendFontChange(String fontName) {
113 try {
114 JSONObject json = new JSONObject();
115 JSONObject valueJson = new JSONObject();
116 valueJson.put("type", "string");
117 valueJson.put("value", fontName);
118 json.put("CharFontName.FamilyName", valueJson);
120 LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND, ".uno:CharFontName", json.toString()));
122 } catch (JSONException e) {
123 e.printStackTrace();
127 private void sendFontSizeChange(String fontSize) {
128 try {
129 JSONObject json = new JSONObject();
130 JSONObject valueJson = new JSONObject();
131 valueJson.put("type", "float");
132 valueJson.put("value", fontSize);
133 json.put("FontHeight.Height", valueJson);
135 LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND, ".uno:FontHeight", json.toString()));
137 } catch (JSONException e) {
138 e.printStackTrace();
142 private void sendFontColorChange(int color, boolean keepAlpha){
143 try {
144 JSONObject json = new JSONObject();
145 JSONObject valueJson = new JSONObject();
146 valueJson.put("type", "long");
147 valueJson.put("value", keepAlpha ? color : 0x00FFFFFF & color);
148 json.put("Color", valueJson);
150 LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND, ".uno:Color", json.toString()));
151 changeFontColorBoxColor(color);
153 } catch (JSONException e) {
154 e.printStackTrace();
159 * 0x00FFFFFF & color operation removes the alpha which is FF,
160 * if we don't remove it, the color value becomes negative which is not recognized by LOK
162 private void sendFontBackColorChange(int color, boolean keepAlpha) {
163 try {
164 JSONObject json = new JSONObject();
165 JSONObject valueJson = new JSONObject();
166 valueJson.put("type", "long");
167 valueJson.put("value", keepAlpha ? color : 0x00FFFFFF & color);
168 if(mActivity.getTileProvider().isSpreadsheet()){
169 json.put("BackgroundColor", valueJson);
170 LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND, ".uno:BackgroundColor", json.toString()));
171 }else {
172 json.put("CharBackColor", valueJson);
173 LOKitShell.sendEvent(new LOEvent(LOEvent.UNO_COMMAND, ".uno:CharBackColor", json.toString()));
176 changeFontBackColorBoxColor(color);
178 } catch (JSONException e) {
179 e.printStackTrace();
184 @Override
185 public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
186 if (mFontList.isEmpty() || !mFontNameSpinnerSet)
187 return;
188 if (parent == mActivity.findViewById(R.id.font_name_spinner)) {
189 String currentFontSelected = parent.getItemAtPosition(pos).toString();
190 if (!currentFontSelected.equals(mCurrentFontSelected)) {
191 mCurrentFontSelected = currentFontSelected;
192 sendFontChange(mCurrentFontSelected);
194 } else if (parent == mActivity.findViewById(R.id.font_size_spinner)) {
195 String currentFontSizeSelected = parent.getItemAtPosition(pos).toString();
196 if (!currentFontSizeSelected.equals(mCurrentFontSizeSelected)) {
197 mCurrentFontSizeSelected = currentFontSizeSelected;
198 sendFontSizeChange(mCurrentFontSizeSelected);
203 @Override
204 public void onNothingSelected(AdapterView parent) {
205 // Do nothing.
208 public void parseJson(String json) {
209 mFontList.clear();
210 mFontSizes.clear();
211 try {
212 JSONObject jObject = new JSONObject(json);
213 final JSONArray fontNameArray = jObject.getJSONArray("FontNames");
214 for (int i = 0; i < fontNameArray.length(); i++) {
215 mFontList.add(fontNameArray.getString(i));
218 final JSONArray fontSizeArray = jObject.getJSONArray("FontSizes");
219 for (int i = 0; i < fontSizeArray.length(); i++) {
220 mFontSizes.add(fontSizeArray.getString(i));
222 } catch (JSONException e) {
223 e.printStackTrace();
227 public void setupFontViews() {
228 LOKitShell.getMainHandler().post(new Runnable() {
229 public void run() {
230 setupFontNameSpinner();
231 setupFontSizeSpinner();
232 setupColorPicker();
233 setupBackColorPicker();
238 private void setupFontNameSpinner() {
239 Spinner fontSpinner = mActivity.findViewById(R.id.font_name_spinner);
240 ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(mActivity, android.R.layout.simple_spinner_item, mFontList);
241 dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
242 fontSpinner.setAdapter(dataAdapter);
245 private void setupFontSizeSpinner() {
246 Spinner fontSizeSpinner = mActivity.findViewById(R.id.font_size_spinner);
247 ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(mActivity, android.R.layout.simple_spinner_item, mFontSizes);
248 dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
249 fontSizeSpinner.setAdapter(dataAdapter);
252 private void setupColorPicker(){
253 LinearLayout colorPickerLayout = mActivity.findViewById(R.id.toolbar_color_picker);
255 RecyclerView recyclerView = colorPickerLayout.findViewById(R.id.fontColorView);
256 GridLayoutManager gridLayoutManager = new GridLayoutManager(mActivity, 11, GridLayoutManager.VERTICAL, true);
257 recyclerView.setHasFixedSize(true);
258 recyclerView.setLayoutManager(gridLayoutManager);
262 RecyclerView recyclerView2 = colorPickerLayout.findViewById(R.id.fontColorViewSub);
263 GridLayoutManager gridLayoutManager2 = new GridLayoutManager(mActivity,4);
264 recyclerView2.setHasFixedSize(true);
265 recyclerView2.addItemDecoration(new RecyclerView.ItemDecoration() {
267 @Override
268 public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
269 outRect.bottom = 3;
270 outRect.top = 3;
271 outRect.left = 3;
272 outRect.right = 3;
275 recyclerView2.setLayoutManager(gridLayoutManager2);
277 ColorPaletteAdapter colorPaletteAdapter = new ColorPaletteAdapter(mActivity, colorPaletteListener);
278 recyclerView2.setAdapter(colorPaletteAdapter);
280 this.colorPickerAdapter = new ColorPickerAdapter(mActivity, colorPaletteAdapter, colorPaletteListener);
281 recyclerView.setAdapter(colorPickerAdapter);
282 RelativeLayout fontColorPicker = mActivity.findViewById(R.id.font_color_picker);
283 ImageButton fontColorPickerButton = mActivity.findViewById(R.id.font_color_picker_button);
284 View.OnClickListener clickListener = new View.OnClickListener(){
285 @Override
286 public void onClick(View view) {
287 toolBarBottomBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
288 colorPickerBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
289 mActivity.findViewById(R.id.search_toolbar).setVisibility(View.GONE);
292 LinearLayout toolbarBottomLayout = mActivity.findViewById(R.id.toolbar_bottom);
293 colorPickerBehavior = BottomSheetBehavior.from(colorPickerLayout);
294 toolBarBottomBehavior = BottomSheetBehavior.from(toolbarBottomLayout);
296 ImageButton pickerGoBackButton = colorPickerLayout.findViewById(R.id.button_go_back_color_picker);
297 pickerGoBackButton.setOnClickListener(new View.OnClickListener() {
298 @Override
299 public void onClick(View view) {
300 toolBarBottomBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
301 colorPickerBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
306 fontColorPicker.setOnClickListener(clickListener);
307 fontColorPickerButton.setOnClickListener(clickListener);
309 final Button autoColorButton = colorPickerLayout.findViewById(R.id.button_auto_color);
310 autoColorButton.setOnClickListener(view -> {
311 sendFontColorChange(COLOR_AUTO, true);
315 private void setupBackColorPicker(){
316 LinearLayout backColorPickerLayout = mActivity.findViewById(R.id.toolbar_back_color_picker);
318 RecyclerView recyclerView = backColorPickerLayout.findViewById(R.id.fontColorView);
319 GridLayoutManager gridLayoutManager = new GridLayoutManager(mActivity, 11, GridLayoutManager.VERTICAL, true);
320 recyclerView.setHasFixedSize(true);
321 recyclerView.setLayoutManager(gridLayoutManager);
325 RecyclerView recyclerView2 = backColorPickerLayout.findViewById(R.id.fontColorViewSub);
326 GridLayoutManager gridLayoutManager2 = new GridLayoutManager(mActivity,4);
327 recyclerView2.setHasFixedSize(true);
328 recyclerView2.addItemDecoration(new RecyclerView.ItemDecoration() {
330 @Override
331 public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
332 outRect.bottom = 3;
333 outRect.top = 3;
334 outRect.left = 3;
335 outRect.right = 3;
338 recyclerView2.setLayoutManager(gridLayoutManager2);
340 ColorPaletteAdapter colorPaletteAdapter = new ColorPaletteAdapter(mActivity, backColorPaletteListener);
341 recyclerView2.setAdapter(colorPaletteAdapter);
343 this.backColorPickerAdapter = new ColorPickerAdapter(mActivity, colorPaletteAdapter, backColorPaletteListener);
344 recyclerView.setAdapter(backColorPickerAdapter);
345 RelativeLayout fontColorPicker = mActivity.findViewById(R.id.font_back_color_picker);
346 ImageButton fontColorPickerButton = mActivity.findViewById(R.id.font_back_color_picker_button);
347 View.OnClickListener clickListener = new View.OnClickListener(){
348 @Override
349 public void onClick(View view) {
350 toolBarBottomBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
351 backColorPickerBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
352 mActivity.findViewById(R.id.search_toolbar).setVisibility(View.GONE);
355 LinearLayout toolbarBottomLayout = mActivity.findViewById(R.id.toolbar_bottom);
356 backColorPickerBehavior = BottomSheetBehavior.from(backColorPickerLayout);
357 toolBarBottomBehavior = BottomSheetBehavior.from(toolbarBottomLayout);
359 ImageButton pickerGoBackButton = backColorPickerLayout.findViewById(R.id.button_go_back_color_picker);
360 pickerGoBackButton.setOnClickListener(new View.OnClickListener() {
361 @Override
362 public void onClick(View view) {
363 toolBarBottomBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
364 backColorPickerBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
369 fontColorPicker.setOnClickListener(clickListener);
370 fontColorPickerButton.setOnClickListener(clickListener);
372 final Button autoColorButton = backColorPickerLayout.findViewById(R.id.button_auto_color);
373 autoColorButton.setOnClickListener(view -> {
374 sendFontBackColorChange(COLOR_AUTO, true);
378 public void selectFont(final String fontName) {
379 LOKitShell.getMainHandler().post(new Runnable() {
380 public void run() {
381 selectFontCurrentThread(fontName);
386 private void selectFontCurrentThread(String fontName) {
387 Spinner spinner = mActivity.findViewById(R.id.font_name_spinner);
388 if (!mFontNameSpinnerSet) {
389 spinner.setOnItemSelectedListener(this);
390 mFontNameSpinnerSet = true;
393 if (fontName.equals(mCurrentFontSelected))
394 return;
396 int position = mFontList.indexOf(fontName);
397 if (position != -1) {
398 mCurrentFontSelected = fontName;
399 spinner.setSelection(position,false);
403 public void selectFontSize(final String fontSize) {
404 LOKitShell.getMainHandler().post(new Runnable() {
405 public void run() {
406 selectFontSizeCurrentThread(fontSize);
411 private void selectFontSizeCurrentThread(String fontSize) {
412 Spinner spinner = mActivity.findViewById(R.id.font_size_spinner);
413 if (!mFontSizeSpinnerSet) {
414 spinner.setOnItemSelectedListener(this);
415 mFontSizeSpinnerSet = true;
418 if (fontSize.equals(mCurrentFontSizeSelected))
419 return;
421 int position = mFontSizes.indexOf(fontSize);
422 if (position != -1) {
423 mCurrentFontSizeSelected = fontSize;
424 spinner.setSelection(position, false);