blob: 896225aa779fa7bcf91dc37e046c50629089cf3b [file] [log] [blame]
Hans Boehm84614952014-11-25 18:46:17 -08001/*
2 * Copyright (C) 2015 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 com.android.calculator2;
18
19import android.content.res.Resources;
20import android.content.Context;
Hans Boehm4a6b7cb2015-04-03 18:41:52 -070021import android.app.Activity;
22import android.util.Log;
Hans Boehm84614952014-11-25 18:46:17 -080023import android.view.View;
Hans Boehm4a6b7cb2015-04-03 18:41:52 -070024import android.widget.Button;
25
Hans Boehm84614952014-11-25 18:46:17 -080026import java.text.DecimalFormatSymbols;
Hans Boehm4a6b7cb2015-04-03 18:41:52 -070027import java.util.HashMap;
28import java.util.Locale;
Hans Boehm84614952014-11-25 18:46:17 -080029
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070030/**
31 * Collection of mapping functions between key ids, characters, internationalized
Justin Klaassene2711cb2015-05-28 11:13:17 -070032 * and non-internationalized characters, etc.
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070033 * <p>
34 * KeyMap instances are not meaningful; everything here is static.
35 * All functions are either pure, or are assumed to be called only from a single UI thread.
36 */
Hans Boehm84614952014-11-25 18:46:17 -080037public class KeyMaps {
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070038 /**
39 * Map key id to corresponding (internationalized) display string.
40 * Pure function.
41 */
Justin Klaassene2711cb2015-05-28 11:13:17 -070042 public static String toString(Context context, int id) {
Hans Boehm84614952014-11-25 18:46:17 -080043 switch(id) {
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070044 case R.id.const_pi:
Justin Klaassene2711cb2015-05-28 11:13:17 -070045 return context.getString(R.string.const_pi);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070046 case R.id.const_e:
Justin Klaassene2711cb2015-05-28 11:13:17 -070047 return context.getString(R.string.const_e);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070048 case R.id.op_sqrt:
Justin Klaassene2711cb2015-05-28 11:13:17 -070049 return context.getString(R.string.op_sqrt);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070050 case R.id.op_fact:
Justin Klaassene2711cb2015-05-28 11:13:17 -070051 return context.getString(R.string.op_fact);
52 case R.id.op_pct:
53 return context.getString(R.string.op_pct);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070054 case R.id.fun_sin:
Justin Klaassene2711cb2015-05-28 11:13:17 -070055 return context.getString(R.string.fun_sin) + context.getString(R.string.lparen);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070056 case R.id.fun_cos:
Justin Klaassene2711cb2015-05-28 11:13:17 -070057 return context.getString(R.string.fun_cos) + context.getString(R.string.lparen);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070058 case R.id.fun_tan:
Justin Klaassene2711cb2015-05-28 11:13:17 -070059 return context.getString(R.string.fun_tan) + context.getString(R.string.lparen);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070060 case R.id.fun_arcsin:
Justin Klaassene2711cb2015-05-28 11:13:17 -070061 return context.getString(R.string.fun_arcsin) + context.getString(R.string.lparen);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070062 case R.id.fun_arccos:
Justin Klaassene2711cb2015-05-28 11:13:17 -070063 return context.getString(R.string.fun_arccos) + context.getString(R.string.lparen);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070064 case R.id.fun_arctan:
Justin Klaassene2711cb2015-05-28 11:13:17 -070065 return context.getString(R.string.fun_arctan) + context.getString(R.string.lparen);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070066 case R.id.fun_ln:
Justin Klaassene2711cb2015-05-28 11:13:17 -070067 return context.getString(R.string.fun_ln) + context.getString(R.string.lparen);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070068 case R.id.fun_log:
Justin Klaassene2711cb2015-05-28 11:13:17 -070069 return context.getString(R.string.fun_log) + context.getString(R.string.lparen);
Hans Boehm4db31b42015-05-31 12:19:05 -070070 case R.id.fun_exp:
71 // Button label doesn't work.
72 return context.getString(R.string.exponential) + context.getString(R.string.lparen);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070073 case R.id.lparen:
Justin Klaassene2711cb2015-05-28 11:13:17 -070074 return context.getString(R.string.lparen);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070075 case R.id.rparen:
Justin Klaassene2711cb2015-05-28 11:13:17 -070076 return context.getString(R.string.rparen);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070077 case R.id.op_pow:
Justin Klaassene2711cb2015-05-28 11:13:17 -070078 return context.getString(R.string.op_pow);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070079 case R.id.op_mul:
Justin Klaassene2711cb2015-05-28 11:13:17 -070080 return context.getString(R.string.op_mul);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070081 case R.id.op_div:
Justin Klaassene2711cb2015-05-28 11:13:17 -070082 return context.getString(R.string.op_div);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070083 case R.id.op_add:
Justin Klaassene2711cb2015-05-28 11:13:17 -070084 return context.getString(R.string.op_add);
Hans Boehm4db31b42015-05-31 12:19:05 -070085 case R.id.op_sqr:
86 // Button label doesn't work.
87 return context.getString(R.string.squared);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070088 case R.id.op_sub:
Justin Klaassene2711cb2015-05-28 11:13:17 -070089 return context.getString(R.string.op_sub);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070090 case R.id.dec_point:
Justin Klaassene2711cb2015-05-28 11:13:17 -070091 return context.getString(R.string.dec_point);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070092 case R.id.digit_0:
Justin Klaassene2711cb2015-05-28 11:13:17 -070093 return context.getString(R.string.digit_0);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070094 case R.id.digit_1:
Justin Klaassene2711cb2015-05-28 11:13:17 -070095 return context.getString(R.string.digit_1);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070096 case R.id.digit_2:
Justin Klaassene2711cb2015-05-28 11:13:17 -070097 return context.getString(R.string.digit_2);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -070098 case R.id.digit_3:
Justin Klaassene2711cb2015-05-28 11:13:17 -070099 return context.getString(R.string.digit_3);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700100 case R.id.digit_4:
Justin Klaassene2711cb2015-05-28 11:13:17 -0700101 return context.getString(R.string.digit_4);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700102 case R.id.digit_5:
Justin Klaassene2711cb2015-05-28 11:13:17 -0700103 return context.getString(R.string.digit_5);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700104 case R.id.digit_6:
Justin Klaassene2711cb2015-05-28 11:13:17 -0700105 return context.getString(R.string.digit_6);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700106 case R.id.digit_7:
Justin Klaassene2711cb2015-05-28 11:13:17 -0700107 return context.getString(R.string.digit_7);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700108 case R.id.digit_8:
Justin Klaassene2711cb2015-05-28 11:13:17 -0700109 return context.getString(R.string.digit_8);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700110 case R.id.digit_9:
Justin Klaassene2711cb2015-05-28 11:13:17 -0700111 return context.getString(R.string.digit_9);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700112 default:
Justin Klaassene2711cb2015-05-28 11:13:17 -0700113 return "";
Hans Boehm84614952014-11-25 18:46:17 -0800114 }
115 }
116
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700117 /**
Hans Boehm8a4f81c2015-07-09 10:41:25 -0700118 * Map key id to corresponding (internationalized) descriptive string that can be used
119 * to correctly read back a formula.
120 * Only used for operators and individual characters; not used inside constants.
121 * Returns null when we don't need a descriptive string.
122 * Pure function.
123 */
124 public static String toDescriptiveString(Context context, int id) {
125 switch(id) {
126 case R.id.op_fact:
127 return context.getString(R.string.desc_op_fact);
128 case R.id.fun_sin:
129 return context.getString(R.string.desc_fun_sin)
130 + " " + context.getString(R.string.desc_lparen);
131 case R.id.fun_cos:
132 return context.getString(R.string.desc_fun_cos)
133 + " " + context.getString(R.string.desc_lparen);
134 case R.id.fun_tan:
135 return context.getString(R.string.desc_fun_tan)
136 + " " + context.getString(R.string.desc_lparen);
137 case R.id.fun_arcsin:
138 return context.getString(R.string.desc_fun_arcsin)
139 + " " + context.getString(R.string.desc_lparen);
140 case R.id.fun_arccos:
141 return context.getString(R.string.desc_fun_arccos)
142 + " " + context.getString(R.string.desc_lparen);
143 case R.id.fun_arctan:
144 return context.getString(R.string.desc_fun_arctan)
145 + " " + context.getString(R.string.desc_lparen);
146 case R.id.fun_ln:
147 return context.getString(R.string.desc_fun_ln)
148 + " " + context.getString(R.string.desc_lparen);
149 case R.id.fun_log:
150 return context.getString(R.string.desc_fun_log)
151 + " " + context.getString(R.string.desc_lparen);
152 case R.id.fun_exp:
153 return context.getString(R.string.desc_fun_exp)
154 + " " + context.getString(R.string.desc_lparen);
155 case R.id.lparen:
156 return context.getString(R.string.desc_lparen);
157 case R.id.rparen:
158 return context.getString(R.string.desc_rparen);
159 case R.id.op_pow:
160 return context.getString(R.string.desc_op_pow);
161 case R.id.dec_point:
162 return context.getString(R.string.desc_dec_point);
163 default:
164 return null;
165 }
166 }
167
168 /**
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700169 * Does a button id correspond to a binary operator?
170 * Pure function.
171 */
Hans Boehm84614952014-11-25 18:46:17 -0800172 public static boolean isBinary(int id) {
173 switch(id) {
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700174 case R.id.op_pow:
175 case R.id.op_mul:
176 case R.id.op_div:
177 case R.id.op_add:
178 case R.id.op_sub:
179 return true;
180 default:
181 return false;
Hans Boehm84614952014-11-25 18:46:17 -0800182 }
183 }
184
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700185 /**
Hans Boehm017de982015-06-10 17:46:03 -0700186 * Does a button id correspond to a function that introduces an implicit lparen?
187 * Pure function.
188 */
189 public static boolean isFunc(int id) {
190 switch(id) {
191 case R.id.fun_sin:
192 case R.id.fun_cos:
193 case R.id.fun_tan:
194 case R.id.fun_arcsin:
195 case R.id.fun_arccos:
196 case R.id.fun_arctan:
197 case R.id.fun_ln:
198 case R.id.fun_log:
199 case R.id.fun_exp:
200 return true;
201 default:
202 return false;
203 }
204 }
205
206 /**
207 * Does a button id correspond to a prefix operator?
208 * Pure function.
209 */
210 public static boolean isPrefix(int id) {
211 switch(id) {
212 case R.id.op_sqrt:
213 case R.id.op_sub:
214 return true;
215 default:
216 return false;
217 }
218 }
219
220 /**
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700221 * Does a button id correspond to a suffix operator?
222 */
Hans Boehm84614952014-11-25 18:46:17 -0800223 public static boolean isSuffix(int id) {
Justin Klaassene2711cb2015-05-28 11:13:17 -0700224 switch (id) {
225 case R.id.op_fact:
226 case R.id.op_pct:
Hans Boehm4db31b42015-05-31 12:19:05 -0700227 case R.id.op_sqr:
Justin Klaassene2711cb2015-05-28 11:13:17 -0700228 return true;
229 default:
230 return false;
231 }
Hans Boehm84614952014-11-25 18:46:17 -0800232 }
233
234 public static final int NOT_DIGIT = 10;
235
Hans Boehm08e8f322015-04-21 13:18:38 -0700236 public static final String ELLIPSIS = "\u2026";
237
Hans Boehm0b9806f2015-06-29 16:07:15 -0700238 public static final char MINUS_SIGN = '\u2212';
239
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700240 /**
241 * Map key id to digit or NOT_DIGIT
242 * Pure function.
243 */
Hans Boehm84614952014-11-25 18:46:17 -0800244 public static int digVal(int id) {
245 switch (id) {
246 case R.id.digit_0:
247 return 0;
248 case R.id.digit_1:
249 return 1;
250 case R.id.digit_2:
251 return 2;
252 case R.id.digit_3:
253 return 3;
254 case R.id.digit_4:
255 return 4;
256 case R.id.digit_5:
257 return 5;
258 case R.id.digit_6:
259 return 6;
260 case R.id.digit_7:
261 return 7;
262 case R.id.digit_8:
263 return 8;
264 case R.id.digit_9:
265 return 9;
266 default:
267 return NOT_DIGIT;
268 }
269 }
270
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700271 /**
272 * Map digit to corresponding key. Inverse of above.
273 * Pure function.
274 */
Hans Boehm84614952014-11-25 18:46:17 -0800275 public static int keyForDigVal(int v) {
276 switch(v) {
277 case 0:
278 return R.id.digit_0;
279 case 1:
280 return R.id.digit_1;
281 case 2:
282 return R.id.digit_2;
283 case 3:
284 return R.id.digit_3;
285 case 4:
286 return R.id.digit_4;
287 case 5:
288 return R.id.digit_5;
289 case 6:
290 return R.id.digit_6;
291 case 7:
292 return R.id.digit_7;
293 case 8:
294 return R.id.digit_8;
295 case 9:
296 return R.id.digit_9;
297 default:
298 return View.NO_ID;
299 }
300 }
301
Hans Boehm425ed0a2015-05-19 18:27:31 -0700302 // The following two are only used for recognizing additional
303 // input characters from a physical keyboard. They are not used
304 // for output internationalization.
305 private static char mDecimalPt;
Hans Boehm84614952014-11-25 18:46:17 -0800306
Hans Boehmffda5282015-05-18 15:00:12 -0700307 private static char mPiChar;
Hans Boehm4a6b7cb2015-04-03 18:41:52 -0700308
Hans Boehmffda5282015-05-18 15:00:12 -0700309 /**
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700310 * Character used as a placeholder for digits that are currently unknown in a result that
311 * is being computed. We initially generate blanks, and then use this as a replacement
312 * during final translation.
Hans Boehmffda5282015-05-18 15:00:12 -0700313 * <p/>
314 * Note: the character must correspond closely to the width of a digit,
315 * otherwise the UI will visibly shift once the computation is finished.
316 */
317 private static final char CHAR_DIGIT_UNKNOWN = '\u2007';
318
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700319 /**
320 * Map typed function name strings to corresponding button ids.
321 * We (now redundantly?) include both localized and English names.
322 */
Hans Boehmffda5282015-05-18 15:00:12 -0700323 private static HashMap<String, Integer> sKeyValForFun;
Hans Boehm4a6b7cb2015-04-03 18:41:52 -0700324
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700325 /**
326 * Result string corresponding to a character in the calculator result.
327 * The string values in the map are expected to be one character long.
328 */
Hans Boehmffda5282015-05-18 15:00:12 -0700329 private static HashMap<Character, String> sOutputForResultChar;
Hans Boehm013969e2015-04-13 20:29:47 -0700330
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700331 /**
332 * Locale string corresponding to preceding map and character constants.
333 * We recompute the map if this is not the current locale.
334 */
Hans Boehmffda5282015-05-18 15:00:12 -0700335 private static String sLocaleForMaps = "none";
Hans Boehm4a6b7cb2015-04-03 18:41:52 -0700336
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700337 /**
338 * Activity to use for looking up buttons.
339 */
340 private static Activity mActivity;
Hans Boehm013969e2015-04-13 20:29:47 -0700341
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700342 /**
343 * Set acttivity used for looking up button labels.
344 * Call only from UI thread.
345 */
Hans Boehm013969e2015-04-13 20:29:47 -0700346 public static void setActivity(Activity a) {
347 mActivity = a;
348 }
349
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700350 /**
351 * Return the button id corresponding to the supplied character or return NO_ID.
352 * Called only by UI thread.
353 */
Hans Boehm013969e2015-04-13 20:29:47 -0700354 public static int keyForChar(char c) {
355 validateMaps();
Hans Boehm84614952014-11-25 18:46:17 -0800356 if (Character.isDigit(c)) {
357 int i = Character.digit(c, 10);
358 return KeyMaps.keyForDigVal(i);
359 }
Hans Boehm84614952014-11-25 18:46:17 -0800360 switch (c) {
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700361 case '.':
362 case ',':
363 return R.id.dec_point;
364 case '-':
Hans Boehm0b9806f2015-06-29 16:07:15 -0700365 case MINUS_SIGN:
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700366 return R.id.op_sub;
367 case '+':
368 return R.id.op_add;
369 case '*':
Hans Boehm0b9806f2015-06-29 16:07:15 -0700370 case '\u00D7': // MULTIPLICATION SIGN
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700371 return R.id.op_mul;
372 case '/':
Hans Boehm0b9806f2015-06-29 16:07:15 -0700373 case '\u00F7': // DIVISION SIGN
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700374 return R.id.op_div;
375 // We no longer localize function names, so they can't start with an 'e' or 'p'.
376 case 'e':
377 case 'E':
378 return R.id.const_e;
379 case 'p':
380 case 'P':
381 return R.id.const_pi;
382 case '^':
383 return R.id.op_pow;
384 case '!':
385 return R.id.op_fact;
Justin Klaassene2711cb2015-05-28 11:13:17 -0700386 case '%':
387 return R.id.op_pct;
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700388 case '(':
389 return R.id.lparen;
390 case ')':
391 return R.id.rparen;
392 default:
393 if (c == mDecimalPt) return R.id.dec_point;
394 if (c == mPiChar) return R.id.const_pi;
395 // pi is not translated, but it might be typable on a Greek keyboard,
Hans Boehm0b9806f2015-06-29 16:07:15 -0700396 // or pasted in, so we check ...
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700397 return View.NO_ID;
Hans Boehm84614952014-11-25 18:46:17 -0800398 }
399 }
Hans Boehm4a6b7cb2015-04-03 18:41:52 -0700400
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700401 /**
402 * Add information corresponding to the given button id to sKeyValForFun, to be used
403 * when mapping keyboard input to button ids.
404 */
Hans Boehm013969e2015-04-13 20:29:47 -0700405 static void addButtonToFunMap(int button_id) {
406 Button button = (Button)mActivity.findViewById(button_id);
Hans Boehm4a6b7cb2015-04-03 18:41:52 -0700407 sKeyValForFun.put(button.getText().toString(), button_id);
408 }
409
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700410 /**
411 * Add information corresponding to the given button to sOutputForResultChar, to be used
412 * when translating numbers on output.
413 */
Hans Boehm013969e2015-04-13 20:29:47 -0700414 static void addButtonToOutputMap(char c, int button_id) {
415 Button button = (Button)mActivity.findViewById(button_id);
416 sOutputForResultChar.put(c, button.getText().toString());
417 }
418
Hans Boehm4a6b7cb2015-04-03 18:41:52 -0700419 // Ensure that the preceding map and character constants are
420 // initialized and correspond to the current locale.
421 // Called only by a single thread, namely the UI thread.
Hans Boehm013969e2015-04-13 20:29:47 -0700422 static void validateMaps() {
Hans Boehm4a6b7cb2015-04-03 18:41:52 -0700423 Locale locale = Locale.getDefault();
424 String lname = locale.toString();
Hans Boehm013969e2015-04-13 20:29:47 -0700425 if (lname != sLocaleForMaps) {
Hans Boehm4a6b7cb2015-04-03 18:41:52 -0700426 Log.v ("Calculator", "Setting local to: " + lname);
427 sKeyValForFun = new HashMap<String, Integer>();
428 sKeyValForFun.put("sin", R.id.fun_sin);
429 sKeyValForFun.put("cos", R.id.fun_cos);
430 sKeyValForFun.put("tan", R.id.fun_tan);
431 sKeyValForFun.put("arcsin", R.id.fun_arcsin);
432 sKeyValForFun.put("arccos", R.id.fun_arccos);
433 sKeyValForFun.put("arctan", R.id.fun_arctan);
434 sKeyValForFun.put("asin", R.id.fun_arcsin);
435 sKeyValForFun.put("acos", R.id.fun_arccos);
436 sKeyValForFun.put("atan", R.id.fun_arctan);
437 sKeyValForFun.put("ln", R.id.fun_ln);
438 sKeyValForFun.put("log", R.id.fun_log);
439 sKeyValForFun.put("sqrt", R.id.op_sqrt); // special treatment
Hans Boehm013969e2015-04-13 20:29:47 -0700440 addButtonToFunMap(R.id.fun_sin);
441 addButtonToFunMap(R.id.fun_cos);
442 addButtonToFunMap(R.id.fun_tan);
443 addButtonToFunMap(R.id.fun_arcsin);
444 addButtonToFunMap(R.id.fun_arccos);
445 addButtonToFunMap(R.id.fun_arctan);
446 addButtonToFunMap(R.id.fun_ln);
447 addButtonToFunMap(R.id.fun_log);
Hans Boehm4a6b7cb2015-04-03 18:41:52 -0700448
449 // Set locale-dependent character "constants"
Hans Boehm013969e2015-04-13 20:29:47 -0700450 mDecimalPt =
Hans Boehm4a6b7cb2015-04-03 18:41:52 -0700451 DecimalFormatSymbols.getInstance().getDecimalSeparator();
Hans Boehm425ed0a2015-05-19 18:27:31 -0700452 // We recognize this in keyboard input, even if we use
453 // a different character.
Hans Boehm013969e2015-04-13 20:29:47 -0700454 Resources res = mActivity.getResources();
Hans Boehm425ed0a2015-05-19 18:27:31 -0700455 mPiChar = 0;
Hans Boehm4a6b7cb2015-04-03 18:41:52 -0700456 String piString = res.getString(R.string.const_pi);
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700457 if (piString.length() == 1) {
458 mPiChar = piString.charAt(0);
459 }
Hans Boehm4a6b7cb2015-04-03 18:41:52 -0700460
Hans Boehm013969e2015-04-13 20:29:47 -0700461 sOutputForResultChar = new HashMap<Character, String>();
462 sOutputForResultChar.put('e', "E");
463 sOutputForResultChar.put('E', "E");
Hans Boehmffda5282015-05-18 15:00:12 -0700464 sOutputForResultChar.put(' ', String.valueOf(CHAR_DIGIT_UNKNOWN));
Hans Boehm08e8f322015-04-21 13:18:38 -0700465 sOutputForResultChar.put(ELLIPSIS.charAt(0), ELLIPSIS);
Hans Boehm995e5eb2016-02-08 11:03:01 -0800466 // Translate numbers for fraction display, but not the separating slash, which appears
467 // to be universal. We also do not translate the ln, sqrt, pi
Hans Boehm013969e2015-04-13 20:29:47 -0700468 sOutputForResultChar.put('/', "/");
Hans Boehm995e5eb2016-02-08 11:03:01 -0800469 sOutputForResultChar.put('(', "(");
470 sOutputForResultChar.put(')', ")");
471 sOutputForResultChar.put('l', "l");
472 sOutputForResultChar.put('n', "n");
473 sOutputForResultChar.put('\u221A', "\u221A"); // SQUARE ROOT
474 sOutputForResultChar.put('\u03C0', "\u03C0"); // GREEK SMALL LETTER PI
Hans Boehm013969e2015-04-13 20:29:47 -0700475 addButtonToOutputMap('-', R.id.op_sub);
Hans Boehm425ed0a2015-05-19 18:27:31 -0700476 addButtonToOutputMap('.', R.id.dec_point);
Hans Boehm013969e2015-04-13 20:29:47 -0700477 for (int i = 0; i <= 9; ++i) {
478 addButtonToOutputMap((char)('0' + i), keyForDigVal(i));
479 }
480
481 sLocaleForMaps = lname;
482
Hans Boehm4a6b7cb2015-04-03 18:41:52 -0700483 }
484 }
485
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700486 /**
487 * Return function button id for the substring of s starting at pos and ending with
488 * the next "(". Return NO_ID if there is none.
489 * We currently check for both (possibly localized) button labels, and standard
490 * English names. (They should currently be the same, and hence this is currently redundant.)
491 * Callable only from UI thread.
492 */
Hans Boehm013969e2015-04-13 20:29:47 -0700493 public static int funForString(String s, int pos) {
494 validateMaps();
Hans Boehm4a6b7cb2015-04-03 18:41:52 -0700495 int parenPos = s.indexOf('(', pos);
496 if (parenPos != -1) {
497 String funString = s.substring(pos, parenPos);
498 Integer keyValue = sKeyValForFun.get(funString);
499 if (keyValue == null) return View.NO_ID;
500 return keyValue;
501 }
502 return View.NO_ID;
503 }
Hans Boehm013969e2015-04-13 20:29:47 -0700504
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700505 /**
506 * Return the localization of the string s representing a numeric answer.
507 * Callable only from UI thread.
Hans Boehm995e5eb2016-02-08 11:03:01 -0800508 * A trailing e is treated as the mathematical constant, not an exponent.
Hans Boehm0b3a9fd2015-05-22 11:36:26 -0700509 */
Hans Boehm013969e2015-04-13 20:29:47 -0700510 public static String translateResult(String s) {
511 StringBuilder result = new StringBuilder();
512 int len = s.length();
513 validateMaps();
514 for (int i = 0; i < len; ++i) {
515 char c = s.charAt(i);
Hans Boehm995e5eb2016-02-08 11:03:01 -0800516 if (i < len - 1 || c != 'e') {
517 String translation = sOutputForResultChar.get(c);
518 if (translation == null) {
519 // Should not get here. Report if we do.
520 Log.v("Calculator", "Bad character:" + c);
521 result.append(String.valueOf(c));
522 } else {
523 result.append(translation);
524 }
Hans Boehm013969e2015-04-13 20:29:47 -0700525 }
526 }
527 return result.toString();
528 }
529
Hans Boehm84614952014-11-25 18:46:17 -0800530}