diff options
15 files changed, 149 insertions, 54 deletions
diff --git a/java/res/layout/suggestions_strip.xml b/java/res/layout/suggestions_strip.xml index d8a65f6e5..9c83542a6 100644 --- a/java/res/layout/suggestions_strip.xml +++ b/java/res/layout/suggestions_strip.xml @@ -42,6 +42,7 @@ android:id="@+id/hint_add_to_dictionary" android:layout_width="match_parent" android:layout_height="match_parent" + android:textAlignment="viewStart" style="?attr/suggestionWordStyle" /> </LinearLayout> </merge> diff --git a/java/res/xml/keys_comma_period_symbols.xml b/java/res/xml/keys_comma_period_symbols.xml index cbdbe2ea2..880fe40d9 100644 --- a/java/res/xml/keys_comma_period_symbols.xml +++ b/java/res/xml/keys_comma_period_symbols.xml @@ -22,7 +22,8 @@ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin" > <Key - latin:keyLabel="," /> + latin:keyLabel="!text/keylabel_for_comma" + latin:moreKeys="!text/more_keys_for_comma" /> <!-- U+2026: "…" HORIZONTAL ELLIPSIS --> <Key latin:keyLabel="." diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java index 9f33fcc0a..4e8eb3ea7 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java @@ -1512,7 +1512,8 @@ public final class KeyboardTextsSet { /* 104 */ "\u061F", /* 105 */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\u00AB|\u00BB,\u00BB|\u00AB", /* 106 */ null, - /* 107 */ "\u061F", + // U+064B: "ً" ARABIC FATHATAN + /* 107 */ "\u064B", /* 108 */ "!text/more_keys_for_arabic_diacritics", /* 109 */ null, /* 110 */ "\u064B", diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 1de965ea9..8f4b2d67e 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1498,8 +1498,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } if (showingAddToDictionaryHint && suggest.mDictionaryFacilitator.isUserDictionaryEnabled()) { - mSuggestionStripView.showAddToDictionaryHint( - suggestion, currentSettings.mHintToSaveText); + mSuggestionStripView.showAddToDictionaryHint(suggestion); } else { // If we're not showing the "Touch again to save", then update the suggestion strip. mHandler.postUpdateSuggestionStrip(); diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java index f23022992..e459e4861 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java +++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java @@ -215,11 +215,12 @@ public class Ver4DictDecoder extends AbstractDictDecoder { if (options.mHasTimestamp) { probability = buffer.readUnsignedByte(); - final int pos = buffer.position(); - // Skip historical info. - buffer.position(pos + FormatSpec.BIGRAM_TIMESTAMP_SIZE - + FormatSpec.BIGRAM_LEVEL_SIZE - + FormatSpec.BIGRAM_COUNTER_SIZE); + // Skip timestamp + buffer.readInt(); + // Skip level + buffer.readUnsignedByte(); + // Skip count + buffer.readUnsignedByte(); } else { probability = bigramFlags & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY; diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java index e4ae64fdc..2979544ae 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java @@ -49,7 +49,6 @@ public final class SettingsValues { // From resources: public final SpacingAndPunctuations mSpacingAndPunctuations; public final int mDelayUpdateOldSuggestions; - public final CharSequence mHintToSaveText; // From preferences, in the same order as xml/prefs.xml: public final boolean mAutoCap; @@ -101,7 +100,6 @@ public final class SettingsValues { // Get the resources mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions); mSpacingAndPunctuations = new SpacingAndPunctuations(res); - mHintToSaveText = res.getText(R.string.hint_add_to_dictionary); // Store the input attributes if (null == inputAttributes) { diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java index 3cd9d9555..5ed42ab00 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java @@ -50,6 +50,7 @@ import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.utils.AutoCorrectionUtils; import com.android.inputmethod.latin.utils.ResourceUtils; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import com.android.inputmethod.latin.utils.ViewLayoutUtils; import java.util.ArrayList; @@ -459,7 +460,7 @@ final class SuggestionStripLayoutHelper { } public void layoutAddToDictionaryHint(final String word, final ViewGroup addToDictionaryStrip, - final int stripWidth, final CharSequence hintText) { + final int stripWidth) { final int width = stripWidth - mDividerWidth - mPadding * 2; final TextView wordView = (TextView)addToDictionaryStrip.findViewById(R.id.word_to_save); @@ -473,13 +474,17 @@ final class SuggestionStripLayoutHelper { final TextView hintView = (TextView)addToDictionaryStrip.findViewById( R.id.hint_add_to_dictionary); - hintView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL | GravityCompat.START); hintView.setTextColor(mColorAutoCorrect); final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip) == ViewCompat.LAYOUT_DIRECTION_RTL); - final String hintWithArrow = (isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW) - + hintText; + final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW; + final Resources res = addToDictionaryStrip.getResources(); + final boolean isRtlSystem = SubtypeLocaleUtils.isRtlLanguage(res.getConfiguration().locale); + final CharSequence hintText = res.getText(R.string.hint_add_to_dictionary); + final String hintWithArrow = (isRtlLanguage == isRtlSystem) + ? (arrow + hintText) : (hintText + arrow); final int hintWidth = width - wordWidth; + hintView.setTextScaleX(1.0f); // Reset textScaleX. final float hintScaleX = getTextScaleX(hintWithArrow, hintWidth, hintView.getPaint()); hintView.setText(hintWithArrow); hintView.setTextScaleX(hintScaleX); diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index 5469ced7a..22804fce1 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -186,8 +186,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick return mStripVisibilityGroup.isShowingAddToDictionaryStrip(); } - public void showAddToDictionaryHint(final String word, final CharSequence hintText) { - mLayoutHelper.layoutAddToDictionaryHint(word, mAddToDictionaryStrip, getWidth(), hintText); + public void showAddToDictionaryHint(final String word) { + mLayoutHelper.layoutAddToDictionaryHint(word, mAddToDictionaryStrip, getWidth()); // {@link TextView#setTag()} is used to hold the word to be added to dictionary. The word // will be extracted at {@link #onClick(View)}. mAddToDictionaryStrip.setTag(word); diff --git a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java new file mode 100644 index 000000000..8eff2e6e7 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin.utils; + +import android.content.Context; +import android.content.SharedPreferences; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.util.Log; + +public final class ImportantNoticeUtils { + private static final String TAG = ImportantNoticeUtils.class.getSimpleName(); + + // The current version number of an important notice. + // This number must be incremented whenever users should see a new important notice. + private static final int CURRENT_IMPORTANT_NOTICE_VERSION = 0; + + // {@link SharedPreferences} name to save the last important notice version that has been + // displayed to users. + private static final String PREFERENCE_NAME = "important_notice"; + private static final String KEY_IMPORTANT_NOTICE_VERSION = "important_notice_version"; + + // Copy of the hidden {@link Settings.Secure#USER_SETUP_COMPLETE} settings key. + // The value is zero until each multiuser completes system setup wizard. + // Caveat: This is a hidden API. + private static final String Settings_Secure_USER_SETUP_COMPLETE = "user_setup_complete"; + private static final int USER_SETUP_IS_NOT_COMPLETE = 0; + + private ImportantNoticeUtils() { + // This utility class is not publicly instantiable. + } + + public static boolean isInSystemSetupWizard(final Context context) { + try { + final int userSetupComplete = Settings.Secure.getInt( + context.getContentResolver(), Settings_Secure_USER_SETUP_COMPLETE); + return userSetupComplete == USER_SETUP_IS_NOT_COMPLETE; + } catch (final SettingNotFoundException e) { + Log.w(TAG, "Can't find settings in Settings.Secure: key=" + + Settings_Secure_USER_SETUP_COMPLETE); + return false; + } + } + + private static SharedPreferences getImportantNoticePreferences(final Context context) { + return context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); + } + + public static boolean hasNewImportantNotice(final Context context) { + final SharedPreferences prefs = getImportantNoticePreferences(context); + final int lastVersion = prefs.getInt(KEY_IMPORTANT_NOTICE_VERSION, 0); + return CURRENT_IMPORTANT_NOTICE_VERSION > lastVersion; + } + + public static void updateLastImportantNoticeVersion(final Context context) { + final SharedPreferences prefs = getImportantNoticePreferences(context); + prefs.edit() + .putInt(KEY_IMPORTANT_NOTICE_VERSION, CURRENT_IMPORTANT_NOTICE_VERSION) + .apply(); + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java index 0d0288923..b3871bfb4 100644 --- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java @@ -347,9 +347,12 @@ public final class SubtypeLocaleUtils { Arrays.sort(SORTED_RTL_LANGUAGES); } - public static boolean isRtlLanguage(final InputMethodSubtype subtype) { - final Locale locale = getSubtypeLocale(subtype); + public static boolean isRtlLanguage(final Locale locale) { final String language = locale.getLanguage(); return Arrays.binarySearch(SORTED_RTL_LANGUAGES, language) >= 0; } + + public static boolean isRtlLanguage(final InputMethodSubtype subtype) { + return isRtlLanguage(getSubtypeLocale(subtype)); + } } diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp index be7a3c228..37a5b3fe4 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp @@ -73,51 +73,58 @@ bool HeaderPolicy::readRequiresGermanUmlautProcessing() const { REQUIRES_GERMAN_UMLAUT_PROCESSING_KEY, false); } -bool HeaderPolicy::writeHeaderToBuffer(BufferWithExtendableBuffer *const bufferToWrite, - const bool updatesLastUpdatedTime, const bool updatesLastDecayedTime, - const int unigramCount, const int bigramCount, const int extendedRegionSize) const { +bool HeaderPolicy::fillInAndWriteHeaderToBuffer(const bool updatesLastUpdatedTime, + const bool updatesLastDecayedTime, const int unigramCount, const int bigramCount, + const int extendedRegionSize, BufferWithExtendableBuffer *const outBuffer) const { int writingPos = 0; - if (!HeaderReadWriteUtils::writeDictionaryVersion(bufferToWrite, mDictFormatVersion, + HeaderReadWriteUtils::AttributeMap attributeMapToWrite(mAttributeMap); + fillInHeader(updatesLastDecayedTime, updatesLastDecayedTime, + unigramCount, bigramCount, extendedRegionSize, &attributeMapToWrite); + if (!HeaderReadWriteUtils::writeDictionaryVersion(outBuffer, mDictFormatVersion, &writingPos)) { return false; } - if (!HeaderReadWriteUtils::writeDictionaryFlags(bufferToWrite, mDictionaryFlags, + if (!HeaderReadWriteUtils::writeDictionaryFlags(outBuffer, mDictionaryFlags, &writingPos)) { return false; } // Temporarily writes a dummy header size. int headerSizeFieldPos = writingPos; - if (!HeaderReadWriteUtils::writeDictionaryHeaderSize(bufferToWrite, 0 /* size */, + if (!HeaderReadWriteUtils::writeDictionaryHeaderSize(outBuffer, 0 /* size */, &writingPos)) { return false; } - HeaderReadWriteUtils::AttributeMap attributeMapTowrite(mAttributeMap); - HeaderReadWriteUtils::setIntAttribute(&attributeMapTowrite, UNIGRAM_COUNT_KEY, unigramCount); - HeaderReadWriteUtils::setIntAttribute(&attributeMapTowrite, BIGRAM_COUNT_KEY, bigramCount); - HeaderReadWriteUtils::setIntAttribute(&attributeMapTowrite, EXTENDED_REGION_SIZE_KEY, - extendedRegionSize); - if (updatesLastUpdatedTime) { - // Set current time as a last updated time. - HeaderReadWriteUtils::setIntAttribute(&attributeMapTowrite, LAST_UPDATED_TIME_KEY, - TimeKeeper::peekCurrentTime()); - } - if (updatesLastDecayedTime) { - // Set current time as a last updated time. - HeaderReadWriteUtils::setIntAttribute(&attributeMapTowrite, LAST_DECAYED_TIME_KEY, - TimeKeeper::peekCurrentTime()); - } - if (!HeaderReadWriteUtils::writeHeaderAttributes(bufferToWrite, &attributeMapTowrite, + if (!HeaderReadWriteUtils::writeHeaderAttributes(outBuffer, &attributeMapToWrite, &writingPos)) { return false; } - // Writes an actual header size. - if (!HeaderReadWriteUtils::writeDictionaryHeaderSize(bufferToWrite, writingPos, + // Writes the actual header size. + if (!HeaderReadWriteUtils::writeDictionaryHeaderSize(outBuffer, writingPos, &headerSizeFieldPos)) { return false; } return true; } +void HeaderPolicy::fillInHeader(const bool updatesLastUpdatedTime, + const bool updatesLastDecayedTime, const int unigramCount, const int bigramCount, + const int extendedRegionSize, HeaderReadWriteUtils::AttributeMap *outAttributeMap) const { + HeaderReadWriteUtils::setIntAttribute(outAttributeMap, UNIGRAM_COUNT_KEY, unigramCount); + HeaderReadWriteUtils::setIntAttribute(outAttributeMap, BIGRAM_COUNT_KEY, bigramCount); + HeaderReadWriteUtils::setIntAttribute(outAttributeMap, EXTENDED_REGION_SIZE_KEY, + extendedRegionSize); + if (updatesLastUpdatedTime) { + // Set current time as the last updated time. + HeaderReadWriteUtils::setIntAttribute(outAttributeMap, LAST_UPDATED_TIME_KEY, + TimeKeeper::peekCurrentTime()); + } + if (updatesLastDecayedTime) { + // Set current time as the last updated time. + HeaderReadWriteUtils::setIntAttribute(outAttributeMap, LAST_DECAYED_TIME_KEY, + TimeKeeper::peekCurrentTime()); + } +} + /* static */ HeaderReadWriteUtils::AttributeMap HeaderPolicy::createAttributeMapAndReadAllAttributes(const uint8_t *const dictBuf) { HeaderReadWriteUtils::AttributeMap attributeMap; diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h index 1208d2c2a..d65315212 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h @@ -149,9 +149,13 @@ class HeaderPolicy : public DictionaryHeaderStructurePolicy { void readHeaderValueOrQuestionMark(const char *const key, int *outValue, int outValueSize) const; - bool writeHeaderToBuffer(BufferWithExtendableBuffer *const bufferToWrite, - const bool updatesLastUpdatedTime, const bool updatesLastDecayedTime, - const int unigramCount, const int bigramCount, const int extendedRegionSize) const; + bool fillInAndWriteHeaderToBuffer(const bool updatesLastUpdatedTime, + const bool updatesLastDecayedTime, const int unigramCount, const int bigramCount, + const int extendedRegionSize, BufferWithExtendableBuffer *const outBuffer) const; + + void fillInHeader(const bool updatesLastUpdatedTime, const bool updatesLastDecayedTime, + const int unigramCount, const int bigramCount, const int extendedRegionSize, + HeaderReadWriteUtils::AttributeMap *outAttributeMap) const; private: DISALLOW_COPY_AND_ASSIGN(HeaderPolicy); diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp index 43227635c..b6f813c75 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp @@ -39,8 +39,9 @@ void Ver4PatriciaTrieWritingHelper::writeToDictFile(const char *const dictDirPat BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE); const int extendedRegionSize = headerPolicy->getExtendedRegionSize() + mBuffers->getTrieBuffer()->getUsedAdditionalBufferSize(); - if (!headerPolicy->writeHeaderToBuffer(&headerBuffer, false /* updatesLastUpdatedTime */, - false /* updatesLastDecayedTime */, unigramCount, bigramCount, extendedRegionSize)) { + if (!headerPolicy->fillInAndWriteHeaderToBuffer(false /* updatesLastUpdatedTime */, + false /* updatesLastDecayedTime */, unigramCount, bigramCount, extendedRegionSize, + &headerBuffer)) { AKLOGE("Cannot write header structure to buffer. updatesLastUpdatedTime: %d, " "updatesLastDecayedTime: %d, unigramCount: %d, bigramCount: %d, " "extendedRegionSize: %d", false, false, unigramCount, bigramCount, @@ -62,9 +63,9 @@ void Ver4PatriciaTrieWritingHelper::writeToDictFileWithGC(const int rootPtNodeAr } BufferWithExtendableBuffer headerBuffer( BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE); - if (!headerPolicy->writeHeaderToBuffer(&headerBuffer, true /* updatesLastUpdatedTime */, + if (!headerPolicy->fillInAndWriteHeaderToBuffer(true /* updatesLastUpdatedTime */, true /* updatesLastDecayedTime */, unigramCount, bigramCount, - 0 /* extendedRegionSize */)) { + 0 /* extendedRegionSize */, &headerBuffer)) { return; } dictBuffers.get()->flushHeaderAndDictBuffers(dictDirPath, &headerBuffer); diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp index 442373b29..1e57a0b5d 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp @@ -48,9 +48,9 @@ const char *const DictFileWritingUtils::TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE = HeaderPolicy headerPolicy(FormatUtils::VERSION_4, attributeMap); Ver4DictBuffers::Ver4DictBuffersPtr dictBuffers = Ver4DictBuffers::createVer4DictBuffers(&headerPolicy); - headerPolicy.writeHeaderToBuffer(dictBuffers.get()->getWritableHeaderBuffer(), - true /* updatesLastUpdatedTime */, true /* updatesLastDecayedTime */, - 0 /* unigramCount */, 0 /* bigramCount */, 0 /* extendedRegionSize */); + headerPolicy.fillInAndWriteHeaderToBuffer(true /* updatesLastUpdatedTime */, + true /* updatesLastDecayedTime */, 0 /* unigramCount */, 0 /* bigramCount */, + 0 /* extendedRegionSize */, dictBuffers.get()->getWritableHeaderBuffer()); if (!DynamicPtWritingUtils::writeEmptyDictionary( dictBuffers.get()->getWritableTrieBuffer(), 0 /* rootPos */)) { AKLOGE("Empty ver4 dictionary structure cannot be created on memory."); diff --git a/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml index 5bcfe7fc9..a053a8885 100644 --- a/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml @@ -87,7 +87,6 @@ <string name="keylabel_for_tablet_comma">"،"</string> <string name="keyhintlabel_for_tablet_comma">"؟"</string> <string name="more_keys_for_tablet_comma">"!fixedColumnOrder!4,:,!,؟,؛,-,/,«|»,»|«"</string> - <string name="keyhintlabel_for_period">"؟"</string> <!-- U+FDFC: "﷼" RIAL SIGN --> <string name="keylabel_for_currency">﷼</string> <!-- U+061F: "؟" ARABIC QUESTION MARK |