· 5 years ago · Jun 09, 2020, 12:30 PM
1/*
2 * Copyright (C) 2008-2009 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.saginawtyllc.badmoji.keyboard;
18
19import android.app.Dialog;
20import android.content.ClipDescription;
21import android.content.ContentResolver;
22import android.content.ContentValues;
23import android.content.Context;
24import android.content.CursorLoader;
25import android.content.Intent;
26import android.database.Cursor;
27import android.inputmethodservice.InputMethodService;
28import android.inputmethodservice.Keyboard;
29import android.inputmethodservice.KeyboardView;
30import android.net.Uri;
31import android.os.AsyncTask;
32import android.os.Build;
33import android.os.Environment;
34import android.os.IBinder;
35import android.os.VibrationEffect;
36import android.os.Vibrator;
37import android.provider.BaseColumns;
38import android.provider.MediaStore;
39import android.provider.UserDictionary;
40import android.text.InputType;
41import android.text.TextUtils;
42import android.text.method.MetaKeyKeyListener;
43import android.util.Log;
44import android.view.KeyCharacterMap;
45import android.view.KeyEvent;
46import android.view.View;
47import android.view.Window;
48import android.view.inputmethod.CompletionInfo;
49import android.view.inputmethod.EditorInfo;
50import android.view.inputmethod.InputConnection;
51import android.view.inputmethod.InputMethodManager;
52import android.view.inputmethod.InputMethodSubtype;
53import android.view.textservice.SentenceSuggestionsInfo;
54import android.view.textservice.SpellCheckerSession;
55import android.view.textservice.SuggestionsInfo;
56import android.view.textservice.TextInfo;
57import android.view.textservice.TextServicesManager;
58import android.widget.AbsListView;
59import android.widget.ArrayAdapter;
60import android.widget.ImageView;
61import android.widget.LinearLayout;
62import android.widget.ListView;
63import android.widget.SimpleCursorAdapter;
64import android.widget.TextView;
65
66import androidx.core.content.ContextCompat;
67import androidx.core.view.inputmethod.EditorInfoCompat;
68import androidx.core.view.inputmethod.InputConnectionCompat;
69import androidx.core.view.inputmethod.InputContentInfoCompat;
70import androidx.recyclerview.widget.RecyclerView;
71import androidx.viewpager2.widget.ViewPager2;
72
73import com.google.gson.Gson;
74import com.saginawtyllc.badmoji.R;
75import com.saginawtyllc.badmoji.adapter.EmoticonAdapter;
76import com.saginawtyllc.badmoji.adapter.EmoticonFEmaleAdapter;
77import com.saginawtyllc.badmoji.adapter.KeyboardHeaderAdapter;
78import com.saginawtyllc.badmoji.adapter.ViewPagerSoftKeyAdapter;
79import com.saginawtyllc.badmoji.interfaces.EmoticonClickListener;
80import com.saginawtyllc.badmoji.interfaces.OnFemaleEmoticonClick;
81import com.saginawtyllc.badmoji.model.CategoryHeaderModel;
82import com.saginawtyllc.badmoji.model.EmoticonFinalData;
83import com.saginawtyllc.badmoji.model.StatsRequestModel;
84import com.saginawtyllc.badmoji.model.StatsResponseModel;
85import com.saginawtyllc.badmoji.storage.K;
86import com.saginawtyllc.badmoji.utils.CommonUtils;
87import com.saginawtyllc.badmoji.utils.Constant;
88import com.saginawtyllc.badmoji.utils.GridSpacingItemDecoration;
89import com.saginawtyllc.badmoji.utils.NetworkUtils;
90import com.saginawtyllc.badmoji.webservice.StatsApi;
91
92import java.io.File;
93import java.io.FileOutputStream;
94import java.io.IOException;
95import java.io.InputStream;
96import java.io.OutputStream;
97import java.net.URL;
98import java.util.ArrayList;
99import java.util.HashMap;
100import java.util.List;
101import java.util.Locale;
102import java.util.Set;
103
104import ir.ayhansalami.wordprediction.Predictor;
105import ir.ayhansalami.wordprediction.enums.LanguageEnum;
106import ir.ayhansalami.wordprediction.listeners.OnPredictListener;
107
108/**
109 * Example of writing an input method for a soft keyboard. This code is
110 * focused on simplicity over completeness, so it should in no way be considered
111 * to be a complete soft keyboard implementation. Its purpose is to provide
112 * a basic example for how you would get started writing an input method, to
113 * be fleshed out as appropriate.
114 */
115public class SoftKeyboard extends InputMethodService implements
116 KeyboardView.OnKeyboardActionListener, SpellCheckerSession.SpellCheckerSessionListener,
117 EmoticonClickListener, OnFemaleEmoticonClick,
118 StatsApi.StatsApiListener {
119 public static final String TAG = "SoftKeyboard";
120 static final boolean DEBUG = false;
121 /**
122 * This boolean indicates the optional example code for performing
123 * processing of hard keys in addition to regular text generation
124 * from on-screen interaction. It would be used for input methods that
125 * perform language translations (such as converting text entered on
126 * a QWERTY keyboard to Chinese), but may not be used for input methods
127 * that are primarily intended to be used for on-screen text entry.
128 */
129 static final boolean PROCESS_HARD_KEYS = true;
130 private static final String PROVIDER_NAME = "badmoji.bigbadmoji.images";
131 private static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/images");
132 private static final int NOT_A_LENGTH = -1;
133 private InputMethodManager mInputMethodManager;
134 private LinearLayout keyboardParent;
135 private LinearLayout llMaleButton;
136 private LinearLayout llFemaleButton;
137 private LinearLayout llKeyboardButton;
138 private RecyclerView rvEmoticonsParent;
139 private TextView debugger;
140 private LatinKeyboardView mInputView;
141 private CandidateView mCandidateView;
142 private CompletionInfo[] mCompletions;
143 private StringBuilder mComposing = new StringBuilder();
144 private boolean mPredictionOn;
145 private boolean mCompletionOn;
146 private int mLastDisplayWidth;
147 private boolean mCapsLock;
148 private long mLastShiftTime;
149 private long mMetaState;
150 private EmoticonAdapter emoticonAdapter;
151 private EmoticonFEmaleAdapter emoticonFEmaleAdapter;
152 private LatinKeyboard mSymbolsKeyboard;
153 private LatinKeyboard mSymbolsShiftedKeyboard;
154 private LatinKeyboard mQwertyKeyboard;
155 private LatinKeyboard mCurKeyboard;
156 private String mWordSeparators;
157 private SpellCheckerSession mScs;
158 private List<String> mSuggestions;
159 private boolean pngSupported = false;
160 private ArrayList<EmoticonFinalData> arrEmotiList = new ArrayList<>();
161 private ArrayList<EmoticonFinalData> arrFemaleEmoticonList = new ArrayList<>();
162 private SimpleCursorAdapter adapter;
163 private ListView listView;
164 private ImageView ivDummy;
165
166 private RecyclerView rvHeader;
167 private ArrayList<CategoryHeaderModel> categoryHeader = new ArrayList<>();
168 private boolean isMale = true;
169
170 private Uri dummyURI;
171 private int spanCount = 5;
172
173 private int suggestionSize = 0;
174
175 String itemClientName[] = {};
176 ArrayAdapter<String> clientNameAdapter;
177 ArrayList<String> clientNameList = new ArrayList<String>();
178
179 private Predictor predictor;
180 private LanguageEnum currentLanguage = LanguageEnum.EN;
181 private String currentInputString = "";
182
183 //Dheeraj : this section is add to implement ViewPager for swiping
184
185 private ViewPager2 vpEmoticonsParent;
186 private int pos = 0;
187 private KeyboardHeaderAdapter keyboardHeaderAdapter;
188 private ViewPagerSoftKeyAdapter viewPagerSoftKeyAdapter;
189 private Set<Integer> keySet;
190 private ArrayList<Integer> listOfKeys;
191 private ArrayList<Integer> tabOrder;
192 private ArrayList<ArrayList<EmoticonFinalData>> listOfValues;
193 private HashMap<Integer, ArrayList<EmoticonFinalData>> map;
194 //private Vibrator vibrator;
195
196 final View.OnClickListener mButtonClickListener = new View.OnClickListener() {
197 public void onClick(View v) {
198 switch (v.getId()) {
199 case R.id.male_button:
200 if (pngSupported) {
201 llMaleButton.setBackground(ContextCompat.getDrawable(getApplicationContext(), R.drawable.back_solid_curve_stroke_red));
202 llFemaleButton.setBackground(ContextCompat.getDrawable(getApplicationContext(), R.drawable.back_solid_curve_white));
203 llKeyboardButton.setBackground(ContextCompat.getDrawable(getApplicationContext(), R.drawable.back_solid_curve_white));
204 mInputView.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.colorKeyboardBackground));
205 mInputView.setVisibility(View.GONE);
206 vpEmoticonsParent.setVisibility(View.VISIBLE);
207 rvHeader.setVisibility(View.VISIBLE);
208
209 ////
210 setCandidatesViewShown(false);
211 ////
212
213
214 ///For List
215 isMale = true;
216 // pos = 0;
217 setCategoryHeader();
218 if (K.isDownloaded() && K.getMaleCategoryMap(K.maleCategoryMap) != null) {
219 updateViewPager();
220 }
221
222 } else {
223 llMaleButton.setVisibility(View.GONE);
224 llFemaleButton.setVisibility(View.GONE);
225 llKeyboardButton.setVisibility(View.GONE);
226 mInputView.setVisibility(View.VISIBLE);
227 rvHeader.setVisibility(View.GONE);
228
229 }
230 break;
231
232 case R.id.female_button:
233 if (pngSupported) {
234 llMaleButton.setBackground(ContextCompat.getDrawable(getApplicationContext(), R.drawable.back_solid_curve_white));
235 llFemaleButton.setBackground(ContextCompat.getDrawable(getApplicationContext(), R.drawable.back_solid_curve_stroke_red));
236 llKeyboardButton.setBackground(ContextCompat.getDrawable(getApplicationContext(), R.drawable.back_solid_curve_white));
237 mInputView.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.colorKeyboardBackground));
238 mInputView.setVisibility(View.GONE);
239 vpEmoticonsParent.setVisibility(View.VISIBLE);
240 rvHeader.setVisibility(View.VISIBLE);
241
242 ////
243 setCandidatesViewShown(false);
244 ////
245
246 ///For List
247 isMale = false;
248 setCategoryHeader();
249 if (K.isFemaleDownloaded() && K.getFemaleCategoryMap(K.femaleCategoryMap) != null) {
250 updateViewPager();
251 }
252
253 } else {
254 llMaleButton.setVisibility(View.GONE);
255 llFemaleButton.setVisibility(View.GONE);
256 llKeyboardButton.setVisibility(View.GONE);
257 mInputView.setVisibility(View.VISIBLE);
258 rvHeader.setVisibility(View.GONE);
259
260 }
261 break;
262
263 case R.id.keyboard_button:
264 if (pngSupported) {
265 llMaleButton.setBackground(ContextCompat.getDrawable(getApplicationContext(), R.drawable.back_solid_curve_white));
266 llFemaleButton.setBackground(ContextCompat.getDrawable(getApplicationContext(), R.drawable.back_solid_curve_white));
267 llKeyboardButton.setBackground(ContextCompat.getDrawable(getApplicationContext(), R.drawable.back_solid_curve_stroke_red));
268 mInputView.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.candidate_background));
269 mInputView.setVisibility(View.VISIBLE);
270 vpEmoticonsParent.setVisibility(View.GONE);
271 rvHeader.setVisibility(View.GONE);
272
273 ////
274 setCandidatesViewShown(true);
275 ////
276
277 } else {
278 llMaleButton.setVisibility(View.GONE);
279 llFemaleButton.setVisibility(View.GONE);
280 llKeyboardButton.setVisibility(View.GONE);
281 mInputView.setVisibility(View.VISIBLE);
282 rvHeader.setVisibility(View.GONE);
283
284 }
285 break;
286 }
287 }
288 };
289
290 @Override
291 public void onComputeInsets(Insets outInsets) {
292 super.onComputeInsets(outInsets);
293 if (!isFullscreenMode()) {
294 outInsets.contentTopInsets = outInsets.visibleTopInsets;
295 }
296 }
297
298
299 /**
300 * use to set adapter data for male emoji
301 *
302 * @param type
303 */
304 private void setListForMale(int type) {
305 if (arrEmotiList != null && arrEmotiList.size() > 0) {
306 arrEmotiList.clear();
307 }
308 Log.d(TAG, "SomeText: " + new Gson().toJson(K.getMaleCategoryMap(K.maleCategoryMap)));
309 switch (type) {
310 case Constant.ANGRY:
311 if (K.getMaleCategoryMap(K.maleCategoryMap).get(Constant.ANGRY) != null) {
312 arrEmotiList = K.getMaleCategoryMap(K.maleCategoryMap).get(Constant.ANGRY);
313 }
314 emoticonAdapter.updateList(arrEmotiList);
315 break;
316 case Constant.FLIRTY:
317 if (K.getMaleCategoryMap(K.maleCategoryMap).get(Constant.FLIRTY) != null) {
318 arrEmotiList = K.getMaleCategoryMap(K.maleCategoryMap).get(Constant.FLIRTY);
319 }
320 emoticonAdapter.updateList(arrEmotiList);
321 break;
322 case Constant.GENERAL:
323 if (K.getMaleCategoryMap(K.maleCategoryMap).get(Constant.GENERAL) != null) {
324 arrEmotiList = K.getMaleCategoryMap(K.maleCategoryMap).get(Constant.GENERAL);
325 }
326 emoticonAdapter.updateList(arrEmotiList);
327 break;
328 case Constant.HOLIDAY:
329 if (K.getMaleCategoryMap(K.maleCategoryMap).get(Constant.HOLIDAY) != null) {
330 arrEmotiList = K.getMaleCategoryMap(K.maleCategoryMap).get(Constant.HOLIDAY);
331 }
332 emoticonAdapter.updateList(arrEmotiList);
333 break;
334 case Constant.PARTY:
335 if (K.getMaleCategoryMap(K.maleCategoryMap).get(Constant.PARTY) != null) {
336 arrEmotiList = K.getMaleCategoryMap(K.maleCategoryMap).get(Constant.PARTY);
337 }
338 emoticonAdapter.updateList(arrEmotiList);
339 break;
340 default:
341 break;
342 }
343 }
344
345 /**
346 * use to set adapter data for female emoji
347 *
348 * @param type
349 */
350 private void setListForFemale(int type) {
351 if (arrEmotiList != null && arrEmotiList.size() > 0) {
352 arrEmotiList.clear();
353 }
354 switch (type) {
355 case Constant.ANGRY:
356 if (K.getFemaleCategoryMap(K.femaleCategoryMap).get(Constant.ANGRY) != null) {
357 arrEmotiList = K.getFemaleCategoryMap(K.femaleCategoryMap).get(Constant.ANGRY);
358 }
359 emoticonAdapter.updateList(arrEmotiList);
360 break;
361 case Constant.FLIRTY:
362 if (K.getFemaleCategoryMap(K.femaleCategoryMap).get(Constant.FLIRTY) != null) {
363 arrEmotiList = K.getFemaleCategoryMap(K.femaleCategoryMap).get(Constant.FLIRTY);
364 }
365 emoticonAdapter.updateList(arrEmotiList);
366 break;
367 case Constant.GENERAL:
368 if (K.getFemaleCategoryMap(K.femaleCategoryMap).get(Constant.GENERAL) != null) {
369 arrEmotiList = K.getFemaleCategoryMap(K.femaleCategoryMap).get(Constant.GENERAL);
370 }
371 emoticonAdapter.updateList(arrEmotiList);
372 break;
373 case Constant.HOLIDAY:
374 if (K.getFemaleCategoryMap(K.femaleCategoryMap).get(Constant.HOLIDAY) != null) {
375 arrEmotiList = K.getFemaleCategoryMap(K.femaleCategoryMap).get(Constant.HOLIDAY);
376 }
377 emoticonAdapter.updateList(arrEmotiList);
378 break;
379 case Constant.PARTY:
380 if (K.getFemaleCategoryMap(K.femaleCategoryMap).get(Constant.PARTY) != null) {
381 arrEmotiList = K.getFemaleCategoryMap(K.femaleCategoryMap).get(Constant.PARTY);
382 }
383 emoticonAdapter.updateList(arrEmotiList);
384 break;
385 default:
386 break;
387
388 }
389 }
390
391 //TODO : Dheeraj :Remove after confirmation
392 /*private void initEmojiList() {
393 spanCount = CommonUtils.calculateNoOfColumns(this, 100);
394 rvEmoticonsParent.setLayoutManager(new GridLayoutManager(this, spanCount));
395 rvEmoticonsParent.addItemDecoration(new GridSpacingItemDecoration(spanCount, CommonUtils.dpToPx(4), true));
396 /// this is the decoration part
397
398 emoticonAdapter = new EmoticonAdapter(SoftKeyboard.this, spanCount, arrEmotiList,
399 (emoticonFinalData, position) -> {
400 final File file = getFile(getApplicationContext(), arrEmotiList.get(position).getFullPath());
401 copyFileToInternal(arrEmotiList.get(position).getFullPath(), file);
402 String filename = Uri.parse(arrEmotiList.get(position).getFullPath()).getLastPathSegment();
403 String uriString = "content://com.saginawtyllc.badmoji/" + filename;
404 commitEmoticon(Uri.parse(uriString), emoticonFinalData.getTitle(), emoticonFinalData.getId());
405 }
406 );
407 rvEmoticonsParent.setAdapter(emoticonAdapter);
408 }*/
409
410 /**
411 * ViewPager and it's adapter setup
412 */
413
414 private void setUpViewPager() {
415 pos = 0;
416 reOrderDataSet();
417
418 spanCount = CommonUtils.calculateNoOfColumns(this, 100);
419 vpEmoticonsParent.addItemDecoration(new GridSpacingItemDecoration(spanCount, CommonUtils.dpToPx(4), true));
420
421 viewPagerSoftKeyAdapter = new ViewPagerSoftKeyAdapter(this,
422 spanCount,
423 listOfKeys,
424 listOfValues,
425 (emoticonFinalData, parentPosition, position) ->
426 {
427 final File file = getFile(getApplicationContext(), listOfValues.get(parentPosition).get(position).getFullPath());
428 copyFileToInternal(listOfValues.get(parentPosition).get(position).getFullPath(), file);
429 String filename = Uri.parse(listOfValues.get(parentPosition).get(position).getFullPath()).getLastPathSegment();
430 String uriString = "content://com.saginawtyllc.badmoji/" + filename;
431 commitEmoticon(Uri.parse(uriString), emoticonFinalData.getTitle(), emoticonFinalData.getId());
432 });
433
434 vpEmoticonsParent.setAdapter(viewPagerSoftKeyAdapter);
435
436 vpEmoticonsParent.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
437 @Override
438 public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
439 super.onPageScrolled(position, positionOffset, positionOffsetPixels);
440 pos = position;
441 }
442
443 @Override
444 public void onPageSelected(int position) {
445 super.onPageSelected(position);
446 }
447
448 @Override
449 public void onPageScrollStateChanged(int state) {
450 super.onPageScrollStateChanged(state);
451 if (state == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
452 Log.i(TAG, "onPageScrollStateChanged: " + pos);
453 keyboardHeaderAdapter.updatePosition(pos);//use to update the header section using viewpager position
454 }
455
456 }
457 });
458
459 }
460
461 /**
462 * recreate data set as per selection.
463 */
464 private void reOrderDataSet() {
465 map = null;
466 listOfValues = new ArrayList<>();
467 listOfKeys = new ArrayList<Integer>();
468 tabOrder = new ArrayList<>();
469 if (isMale) {
470 if (K.isDownloaded() && K.getMaleCategoryMap(K.maleCategoryMap) != null) {
471 map = K.getMaleCategoryMap(K.maleCategoryMap);
472 }
473 } else {
474 if (K.isFemaleDownloaded() && K.getFemaleCategoryMap(K.femaleCategoryMap) != null) {
475 map = K.getMaleCategoryMap(K.femaleCategoryMap);
476 }
477 }
478 //Getting Set of keys
479 keySet = map.keySet();
480
481 tabOrder.add(Constant.GENERAL);
482 tabOrder.add(Constant.ANGRY);
483 tabOrder.add(Constant.FLIRTY);
484 tabOrder.add(Constant.PARTY);
485 tabOrder.add(Constant.HOLIDAY);
486
487 for (Integer ord : tabOrder) {
488 for (Integer set : keySet) {
489 if (ord.equals(set)) {
490 listOfKeys.add(set);
491 listOfValues.add(map.get(set));
492 break;
493 }
494 }
495 }
496 }
497
498 //TODO : Dheeraj : re-creation of adapter produces a shrink bug
499
500 /**
501 * update the viewPagerAdapter on change of gender selection.
502 */
503 private void updateViewPager() {
504
505 reOrderDataSet();
506
507 keyboardHeaderAdapter.updatePosition(pos);
508
509 viewPagerSoftKeyAdapter.setUpdate(listOfKeys, listOfValues);
510 viewPagerSoftKeyAdapter.notifyDataSetChanged();
511 }
512
513 private void setCategoryHeader() {
514 if (categoryHeader.size() == 0) {
515 categoryHeader.add(new CategoryHeaderModel(Constant.GENERAL, getString(R.string.label_general)));
516 categoryHeader.add(new CategoryHeaderModel(Constant.ANGRY, getString(R.string.label_angry)));
517 categoryHeader.add(new CategoryHeaderModel(Constant.FLIRTY, getString(R.string.label_flirty)));
518 categoryHeader.add(new CategoryHeaderModel(Constant.PARTY, getString(R.string.label_party)));
519 categoryHeader.add(new CategoryHeaderModel(Constant.HOLIDAY, getString(R.string.label_holiday)));
520 }
521 keyboardHeaderAdapter = new KeyboardHeaderAdapter(this, categoryHeader,
522 (int type, int position) -> {
523 if (isMale) {
524 if (K.isDownloaded() && K.getMaleCategoryMap(K.maleCategoryMap) != null) {
525 // setListForMale(type); //Hidden : Dheeraj :
526 pos = position;
527 vpEmoticonsParent.setCurrentItem(pos, true);
528 }
529 } else {
530 if (K.isFemaleDownloaded() && K.getFemaleCategoryMap(K.femaleCategoryMap) != null) {
531 // setListForFemale(type); //Hidden : Dheeraj :
532 pos = position;
533 vpEmoticonsParent.setCurrentItem(pos, true);
534 }
535 }
536
537 });
538
539 rvHeader.setAdapter(keyboardHeaderAdapter);
540 }
541
542 /**
543 * Converts a file to a content uri, by inserting it into the media store.
544 * Requires this permission: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
545 */
546 protected static Uri convertFileToContentUri(Context context, File file) throws Exception {
547
548 //Uri localImageUri = Uri.fromFile(localImageFile); // Not suitable as it's not a content Uri
549
550 ContentResolver cr = context.getContentResolver();
551 String imagePath = file.getAbsolutePath();
552 String imageName = null;
553 String imageDescription = null;
554 String uriString = MediaStore.Images.Media.insertImage(cr, imagePath, imageName, imageDescription);
555 return Uri.parse(uriString);
556 }
557
558 public static Uri getImageContentUri(Context context, File imageFile) {
559 String filePath = imageFile.getAbsolutePath();
560 Cursor cursor = context.getContentResolver().query(
561 MediaStore.Images.Media.INTERNAL_CONTENT_URI,
562 new String[]{MediaStore.Images.Media._ID},
563 MediaStore.Images.Media.DATA + "=? ",
564 new String[]{filePath}, null);
565 if (cursor != null && cursor.moveToFirst()) {
566 int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
567 cursor.close();
568 return Uri.withAppendedPath(MediaStore.Images.Media.INTERNAL_CONTENT_URI, "" + id);
569 } else {
570 if (imageFile.exists()) {
571 ContentValues values = new ContentValues();
572 values.put(MediaStore.Images.Media.DATA, filePath);
573 return context.getContentResolver().insert(
574 MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
575 } else {
576 return null;
577 }
578 }
579
580// FileProvider.getUriForFile(context, imageFile);
581 }
582
583 /**
584 * Main initialization of the input method component. Be sure to call
585 * to super class.
586 */
587 @Override
588 public void onCreate() {
589 super.onCreate();
590 mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
591 mWordSeparators = getResources().getString(R.string.word_separators);
592 final TextServicesManager tsm = (TextServicesManager) getSystemService(
593 Context.TEXT_SERVICES_MANAGER_SERVICE);
594 mScs = tsm.newSpellCheckerSession(null, Locale.ENGLISH, this, false);
595
596 //Log.d(TAG,"Locale: "+Locale.getDefault().getDisplayLanguage());
597// Toast.makeText(this, "res", Toast.LENGTH_SHORT).show();
598
599// AutoCompleteTextView et_client_name = (AutoCompleteTextView) findViewById(R.id.et_client_name);
600// getFromDictionary();
601// suggestClientName();
602// et_client_name.addTextChangedListener(this);
603 predictor = new Predictor(this);
604
605 }
606
607
608 public void getFromDictionary() {
609 System.out.println("Inside getFromDictionary");
610 ContentResolver resolver = getContentResolver();
611 String[] projection = new String[]{BaseColumns._ID, UserDictionary.Words.WORD};
612 String word = "hello";
613 Cursor cursor = resolver.query(UserDictionary.Words.CONTENT_URI, projection, null, null, null);
614 if (cursor.moveToFirst()) {
615 do {
616 long id = Integer.parseInt(cursor.getString(0));
617 word = cursor.getString(1);
618 // Prepare list for autoCompletion
619 System.out.println("Inside prepareMyList" + word);
620 if (!clientNameList.contains(word))
621 clientNameList.add(word);
622 System.out.println("clientNameList::" + clientNameList);
623 System.out.println("Word from dictionary is::" + word);
624 // do something meaningful
625 } while (cursor.moveToNext());
626 }
627 }
628
629 public void suggestClientName() {
630 String newAdd1 = "hell";
631 if (!clientNameList.contains(newAdd1)) {
632 clientNameList.add(newAdd1);
633 // update the autocomplete words
634// clientNameAdapter = new ArrayAdapter<String>(getActivity(),
635// android.R.layout.simple_dropdown_item_1line, clientNameList);
636// et_client_name.setAdapter(clientNameAdapter);
637 }
638 // display the words in myList for your reference
639 String s = "";
640 for (int i = 0; i < clientNameList.size(); i++) {
641 s += clientNameList.get(i) + "\n";
642 }
643 }
644
645 /**
646 * This is the point where you can do all of your UI initialization. It
647 * is called after creation and any configuration change.
648 */
649 @Override
650 public void onInitializeInterface() {
651 if (mQwertyKeyboard != null) {
652 // Configuration changes can happen after the keyboard gets recreated,
653 // so we need to be able to re-build the keyboards if the available
654 // space has changed.
655 int displayWidth = getMaxWidth();
656 if (displayWidth == mLastDisplayWidth) return;
657 mLastDisplayWidth = displayWidth;
658 }
659 mQwertyKeyboard = new LatinKeyboard(this, R.xml.qwerty);
660 mSymbolsKeyboard = new LatinKeyboard(this, R.xml.symbols);
661 mSymbolsShiftedKeyboard = new LatinKeyboard(this, R.xml.symbols_shift);
662// if (pngSupported)
663// getEmoticons(1, 1);
664
665// ImageDataBase imageDataBase = new ImageDataBase(this);
666 //new String[] {"ID", "IMAGETITLE", "IMAGEURL","IMAGEDESC"},
667
668// Cursor cursor = imageDataBase.getImages(ImageDataBase.TABLE_NAME, null, null, null, null);
669
670
671 }
672
673 /**
674 * Called by the framework when your view for creating input needs to
675 * be generated. This will be called the first time your input method
676 * is displayed, and every time it needs to be re-created such as due to
677 * a configuration change.
678 */
679 @Override
680 public View onCreateInputView() {
681
682 keyboardParent = (LinearLayout) getLayoutInflater().inflate(
683 R.layout.input, null);
684
685 mInputView = keyboardParent.findViewById(R.id.keyboard);//LatinKeyboardView) getLayoutInflater().inflate(
686 // R.layout.input, null);
687
688 mInputView.setOnKeyboardActionListener(this);
689 mInputView.setPreviewEnabled(false);
690 setLatinKeyboard(mQwertyKeyboard);
691
692 /*Paint paint = new Paint();
693 Canvas canvas = new Canvas();
694 paint.setTextAlign(Paint.Align.CENTER);
695 paint.setTextSize(28);
696 paint.setColor(Color.RED);
697 List<Keyboard.Key> keys = mInputView.getKeyboard().getKeys();
698 Toast.makeText(this, "" + mInputView.getKeyboard().getKeys(), Toast.LENGTH_SHORT).show();
699 for (Keyboard.Key key : keys) {
700 if (key.label != null)
701 canvas.drawText(key.label.toString(), key.x, key.y, paint);
702 }
703 mInputView.draw(canvas);*/
704
705 //TODO NOT SURE IF THE BELOW LINES SHOULD BE HERE OR ELSEWHERE
706
707
708 llMaleButton = keyboardParent.findViewById(R.id.male_button);
709 llMaleButton.setOnClickListener(mButtonClickListener);
710
711 llFemaleButton = keyboardParent.findViewById(R.id.female_button);
712 llFemaleButton.setOnClickListener(mButtonClickListener);
713
714 llKeyboardButton = keyboardParent.findViewById(R.id.keyboard_button);
715 llKeyboardButton.setOnClickListener(mButtonClickListener);
716
717 // rvEmoticonsParent = keyboardParent.findViewById(R.id.rvEmoticonsParent);
718
719 listView = (ListView) keyboardParent.findViewById(R.id.lstViewImages);
720 ivDummy = keyboardParent.findViewById(R.id.input_ivDummy);
721
722 rvHeader = keyboardParent.findViewById(R.id.input_emojis_rvHeader);
723
724 vpEmoticonsParent = keyboardParent.findViewById(R.id.vpEmoticonsParent);
725
726
727 setCategoryHeader();
728 setUpViewPager();
729 // initEmojiList();
730 // setListForMale(Constant.GENERAL);
731
732
733 //TODO INITIALIZE ADAPTER AFTER CALLING API TO GET DATA. BUT HERE ?! OR ELSEWHERE ?
734
735 // emoticonAdapter = new EmoticonAdapter()
736
737
738 debugger = keyboardParent.findViewById(R.id.debugger);
739 if (arrEmotiList != null) {
740 debugger.setText("now number of content is " + arrEmotiList.size());
741 }
742
743
744 /*rvEmoticonsParent.addOnScrollListener(new RecyclerView.OnScrollListener() {
745 @Override
746 public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
747 super.onScrollStateChanged(recyclerView, newState);
748 }
749
750 @Override
751 public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
752 super.onScrolled(recyclerView, dx, dy);
753 }
754 });*/
755
756 return keyboardParent;
757 }
758
759 private void setLatinKeyboard(LatinKeyboard nextKeyboard) {
760 final boolean shouldSupportLanguageSwitchKey =
761 mInputMethodManager.shouldOfferSwitchingToNextInputMethod(getToken());
762 nextKeyboard.setLanguageSwitchKeyVisibility(shouldSupportLanguageSwitchKey);
763 mInputView.setKeyboard(nextKeyboard);
764 }
765
766 /**
767 * Called by the framework when your view for showing candidates needs to
768 * be generated, like {@link #onCreateInputView}.
769 */
770 @Override
771 public View onCreateCandidatesView() {
772 View view = getLayoutInflater().inflate(
773 R.layout.my_candidate, null);
774 LinearLayout llDemo = view.findViewById(R.id.llDemo);
775 mCandidateView = new CandidateView(this);
776 mCandidateView.setService(this);
777 setCandidatesViewShown(true);
778 mCandidateView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
779 llDemo.addView(mCandidateView);
780 return view;
781 /*mCandidateView = new CandidateView(this);
782 mCandidateView.setService(this);
783 return mCandidateView;*/
784 }
785
786 public File getTempFile(Context context, String url) {
787
788 File file = null;
789
790 try {
791 String fileName = Uri.parse(url).getLastPathSegment();
792 file = File.createTempFile(fileName, null, context.getExternalCacheDir());
793
794 URL imageUrl = new URL(url);
795 InputStream is = imageUrl.openStream();
796 OutputStream os = new FileOutputStream(file);
797
798 byte[] b = new byte[50000];
799 int length;
800
801 while ((length = is.read(b)) != -1) {
802 os.write(b, 0, length);
803 }
804
805 is.close();
806 os.close();
807
808 } catch (IOException e) {
809 e.printStackTrace();
810 }
811 return file;
812
813
814 }
815
816 private void copyFileToInternal(String url, File file) {
817 try {
818 String fileName = Uri.parse(url).getLastPathSegment();
819
820 file = new File(Environment.getExternalStorageDirectory() + "/" + fileName);
821 if (file.exists()) {
822 file.delete();
823 }
824
825 URL imageUrl = new URL(url);
826 InputStream is = imageUrl.openStream();
827
828// InputStream is = getAssets().open(name);
829
830 File cacheDir = getCacheDir();
831 File outFile = new File(cacheDir, fileName);
832
833 OutputStream os = new FileOutputStream(outFile.getAbsolutePath());
834
835 byte[] buff = new byte[1024];
836 int len;
837 while ((len = is.read(buff)) > 0) {
838 os.write(buff, 0, len);
839 }
840 os.flush();
841 os.close();
842 is.close();
843
844 } catch (IOException e) {
845 e.printStackTrace();
846 }
847 }
848
849 public File getFile(Context context, String url) {
850
851 File file = null;
852
853 try {
854 String fileName = Uri.parse(url).getLastPathSegment();
855
856 file = new File(Environment.getExternalStorageDirectory() + "/" + fileName);
857 if (file.exists()) {
858 file.delete();
859 }
860
861 URL imageUrl = new URL(url);
862 InputStream is = imageUrl.openStream();
863 OutputStream os = new FileOutputStream(file);
864
865 byte[] b = new byte[50000];
866 int length;
867
868 while ((length = is.read(b)) != -1) {
869 os.write(b, 0, length);
870 }
871
872 is.close();
873 os.close();
874
875 } catch (IOException e) {
876 e.printStackTrace();
877 }
878 return file;
879
880 }
881
882 /**
883 * This is the main point where we do our initialization of the input method
884 * to begin operating on an application. At this point we have been
885 * bound to the client, and are now receiving all of the detailed information
886 * about the target of our edits.
887 */
888 @Override
889 public void onStartInput(EditorInfo attribute, boolean restarting) {
890 super.onStartInput(attribute, restarting);
891
892 // Reset our state. We want to do this even if restarting, because
893 // the underlying state of the text editor could have changed in any way.
894 mComposing.setLength(0);
895 updateCandidates();
896
897 if (!restarting) {
898 // Clear shift states.
899 mMetaState = 0;
900 }
901
902 mPredictionOn = false;
903 mCompletionOn = false;
904 mCompletions = null;
905
906 // We are now going to initialize our state based on the type of
907 // text being edited.
908 switch (attribute.inputType & InputType.TYPE_MASK_CLASS) {
909 case InputType.TYPE_CLASS_NUMBER:
910 case InputType.TYPE_CLASS_DATETIME:
911 // Numbers and dates default to the symbols keyboard, with
912 // no extra features.
913 mCurKeyboard = mSymbolsKeyboard;
914 break;
915
916 case InputType.TYPE_CLASS_PHONE:
917 // Phones will also default to the symbols keyboard, though
918 // often you will want to have a dedicated phone keyboard.
919 mCurKeyboard = mSymbolsKeyboard;
920 break;
921
922 case InputType.TYPE_CLASS_TEXT:
923 // This is general text editing. We will default to the
924 // normal alphabetic keyboard, and assume that we should
925 // be doing predictive text (showing candidates as the
926 // user types).
927 mCurKeyboard = mQwertyKeyboard;
928 mPredictionOn = true;
929
930 // We now look for a few special variations of text that will
931 // modify our behavior.
932 int variation = attribute.inputType & InputType.TYPE_MASK_VARIATION;
933 if (variation == InputType.TYPE_TEXT_VARIATION_PASSWORD ||
934 variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
935 // Do not display predictions / what the user is typing
936 // when they are entering a password.
937 mPredictionOn = false;
938 }
939
940 if (variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
941 || variation == InputType.TYPE_TEXT_VARIATION_URI
942 || variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
943 // Our predictions are not useful for e-mail addresses
944 // or URIs.
945 mPredictionOn = false;
946 }
947
948 if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
949 // If this is an auto-complete text view, then our predictions
950 // will not be shown and instead we will allow the editor
951 // to supply their own. We only show the editor's
952 // candidates when in fullscreen mode, otherwise relying
953 // own it displaying its own UI.
954 mPredictionOn = false;
955 mCompletionOn = isFullscreenMode();
956 }
957
958 // We also want to look at the current state of the editor
959 // to decide whether our alphabetic keyboard should start out
960 // shifted.
961 updateShiftKeyState(attribute);
962 break;
963
964 default:
965 // For all unknown input types, default to the alphabetic
966 // keyboard with no special features.
967 mCurKeyboard = mQwertyKeyboard;
968 updateShiftKeyState(attribute);
969 }
970
971 // Update the label on the enter key, depending on what the application
972 // says it will do.
973 mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions);
974 }
975
976 /**
977 * This is called when the user is done editing a field. We can use
978 * this to reset our state.
979 */
980 @Override
981 public void onFinishInput() {
982 super.onFinishInput();
983
984 currentInputString = mComposing.toString();
985 // Clear current composing text and candidates.
986 mComposing.setLength(0);
987 updateCandidates();
988
989 // We only hide the candidates window when finishing input on
990 // a particular editor, to avoid popping the underlying application
991 // up and down if the user is entering text into the bottom of
992 // its window.
993 setCandidatesViewShown(false);
994
995 mCurKeyboard = mQwertyKeyboard;
996 if (mInputView != null) {
997 mInputView.closing();
998 }
999 }
1000
1001 @Override
1002 public void onStartInputView(EditorInfo attribute, boolean restarting) {
1003 super.onStartInputView(attribute, restarting);
1004
1005 String[] mimeTypes = EditorInfoCompat.getContentMimeTypes(attribute);
1006
1007 String allowedMimes = "";
1008
1009 for (String mimeType : mimeTypes) {
1010 allowedMimes = allowedMimes + mimeType + ",";
1011
1012 Log.v("mimetypes", mimeType);
1013
1014 if (ClipDescription.compareMimeTypes(mimeType, "image/png")) {
1015 pngSupported = true;
1016 break;
1017 }
1018 }
1019 Log.d(TAG, "pngSupported: " + pngSupported);
1020 //Toast.makeText(getApplicationContext(), allowedMimes, Toast.LENGTH_LONG).show();
1021
1022
1023 if (pngSupported) {
1024
1025 if (llFemaleButton != null)
1026 llFemaleButton.setVisibility(View.VISIBLE);
1027
1028 if (llMaleButton != null)
1029 llMaleButton.setVisibility(View.VISIBLE);
1030
1031 if (llKeyboardButton != null)
1032 llKeyboardButton.setVisibility(View.VISIBLE);
1033
1034
1035 } else {
1036
1037
1038 if (llFemaleButton != null)
1039 llFemaleButton.setVisibility(View.GONE);
1040
1041 if (llMaleButton != null)
1042 llMaleButton.setVisibility(View.GONE);
1043
1044 if (llKeyboardButton != null)
1045 llKeyboardButton.setVisibility(View.GONE);
1046
1047 if (rvHeader != null)
1048 rvHeader.setVisibility(View.GONE);
1049 }
1050
1051
1052 // Apply the selected keyboard to the input view.
1053 setLatinKeyboard(mCurKeyboard);
1054 mInputView.closing();
1055 final InputMethodSubtype subtype = mInputMethodManager.getCurrentInputMethodSubtype();
1056 mInputView.setSubtypeOnSpaceKey(subtype);
1057 }
1058
1059 @Override
1060 public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) {
1061 mInputView.setSubtypeOnSpaceKey(subtype);
1062 }
1063
1064 /**
1065 * Deal with the editor reporting movement of its cursor.
1066 */
1067 @Override
1068 public void onUpdateSelection(int oldSelStart, int oldSelEnd,
1069 int newSelStart, int newSelEnd,
1070 int candidatesStart, int candidatesEnd) {
1071 super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
1072 candidatesStart, candidatesEnd);
1073
1074 // If the current selection in the text view changes, we should
1075 // clear whatever candidate text we have.
1076 if (mComposing.length() > 0 && (newSelStart != candidatesEnd
1077 || newSelEnd != candidatesEnd)) {
1078 mComposing.setLength(0);
1079 updateCandidates();
1080 InputConnection ic = getCurrentInputConnection();
1081 if (ic != null) {
1082 ic.finishComposingText();
1083 }
1084 }
1085 }
1086
1087 /**
1088 * This tells us about completions that the editor has determined based
1089 * on the current text in it. We want to use this in fullscreen mode
1090 * to show the completions ourself, since the editor can not be seen
1091 * in that situation.
1092 */
1093 @Override
1094 public void onDisplayCompletions(CompletionInfo[] completions) {
1095 if (mCompletionOn) {
1096 mCompletions = completions;
1097 if (completions == null) {
1098 setSuggestions(null, false, false, "");
1099 return;
1100 }
1101
1102 List<String> stringList = new ArrayList<String>();
1103 for (int i = 0; i < completions.length; i++) {
1104 CompletionInfo ci = completions[i];
1105 if (ci != null) stringList.add(ci.getText().toString());
1106 }
1107 setSuggestions(stringList, true, true, "");
1108 }
1109 }
1110
1111 /**
1112 * This translates incoming hard key events in to edit operations on an
1113 * InputConnection. It is only needed when using the
1114 * PROCESS_HARD_KEYS option.
1115 */
1116 private boolean translateKeyDown(int keyCode, KeyEvent event) {
1117 mMetaState = MetaKeyKeyListener.handleKeyDown(mMetaState,
1118 keyCode, event);
1119 int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(mMetaState));
1120 mMetaState = MetaKeyKeyListener.adjustMetaAfterKeypress(mMetaState);
1121 InputConnection ic = getCurrentInputConnection();
1122 if (c == 0 || ic == null) {
1123 return false;
1124 }
1125
1126 boolean dead = false;
1127
1128 if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
1129 dead = true;
1130 c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;
1131 }
1132
1133 if (mComposing.length() > 0) {
1134 char accent = mComposing.charAt(mComposing.length() - 1);
1135 int composed = KeyEvent.getDeadChar(accent, c);
1136
1137 if (composed != 0) {
1138 c = composed;
1139 mComposing.setLength(mComposing.length() - 1);
1140 }
1141 }
1142
1143 onKey(c, null);
1144
1145 return true;
1146 }
1147
1148 /**
1149 * Use this to monitor key events being delivered to the application.
1150 * We get first crack at them, and can either resume them or let them
1151 * continue to the app.
1152 */
1153 @Override
1154 public boolean onKeyDown(int keyCode, KeyEvent event) {
1155
1156 switch (keyCode) {
1157 case KeyEvent.KEYCODE_BACK:
1158 // The InputMethodService already takes care of the back
1159 // key for us, to dismiss the input method if it is shown.
1160 // However, our keyboard could be showing a pop-up window
1161 // that back should dismiss, so we first allow it to do that.
1162 if (event.getRepeatCount() == 0 && mInputView != null) {
1163 if (mInputView.handleBack()) {
1164 return true;
1165 }
1166 }
1167 break;
1168
1169 case KeyEvent.KEYCODE_DEL:
1170
1171 // Special handling of the delete key: if we currently are
1172 // composing text for the user, we want to modify that instead
1173 // of let the application to the delete itself.
1174 if (mComposing.length() > 0) {
1175 onKey(Keyboard.KEYCODE_DELETE, null);
1176 return true;
1177 }
1178 break;
1179
1180 case KeyEvent.KEYCODE_ENTER:
1181 // Let the underlying text editor always handle these.
1182 return false;
1183 default:
1184 // For all other keys, if we want to do transformations on
1185 // text being entered with a hard keyboard, we need to process
1186 // it and do the appropriate action.
1187 /*
1188 if (PROCESS_HARD_KEYS) {
1189 if (keyCode == KeyEvent.KEYCODE_SPACE
1190 && (event.getMetaState()&KeyEvent.META_ALT_ON) != 0) {
1191 // A silly example: in our input method, Alt+Space
1192 // is a shortcut for 'android' in lower case.
1193 InputConnection ic = getCurrentInputConnection();
1194 if (ic != null) {
1195 // First, tell the editor that it is no longer in the
1196 // shift state, since we are consuming this.
1197 ic.clearMetaKeyStates(KeyEvent.META_ALT_ON);
1198 keyDownUp(KeyEvent.KEYCODE_A);
1199 keyDownUp(KeyEvent.KEYCODE_N);
1200 keyDownUp(KeyEvent.KEYCODE_D);
1201 keyDownUp(KeyEvent.KEYCODE_R);
1202 keyDownUp(KeyEvent.KEYCODE_O);
1203 keyDownUp(KeyEvent.KEYCODE_I);
1204 keyDownUp(KeyEvent.KEYCODE_D);
1205 // And we consume this event.
1206 return true;
1207 }
1208 }
1209 if (mPredictionOn && translateKeyDown(keyCode, event)) {
1210 return true;
1211 }
1212 }*/
1213 }
1214
1215 return super.onKeyDown(keyCode, event);
1216 }
1217
1218 /**
1219 * Use this to monitor key events being delivered to the application.
1220 * We get first crack at them, and can either resume them or let them
1221 * continue to the app.
1222 */
1223 @Override
1224 public boolean onKeyUp(int keyCode, KeyEvent event) {
1225 // If we want to do transformations on text being entered with a hard
1226 // keyboard, we need to process the up events to update the meta key
1227 // state we are tracking.
1228 if (PROCESS_HARD_KEYS) {
1229 if (mPredictionOn) {
1230 mMetaState = MetaKeyKeyListener.handleKeyUp(mMetaState,
1231 keyCode, event);
1232 }
1233 }
1234
1235
1236 return super.onKeyUp(keyCode, event);
1237 }
1238
1239 /**
1240 * Helper function to commit any text being composed in to the editor.
1241 */
1242 private void commitTyped(InputConnection inputConnection) {
1243 if (mComposing.length() > 0) {
1244 inputConnection.commitText(mComposing, mComposing.length());
1245 mComposing.setLength(0);
1246 updateCandidates();
1247 }
1248 }
1249
1250 public void commitEmoticonDummy(Uri contentUri, String imageDescription) {
1251// Toast.makeText(this, "" + imageDescription, Toast.LENGTH_SHORT).show();
1252
1253// commitEmoticon(contentUri, imageDescription);
1254
1255 }
1256
1257 /**
1258 * Commits a GIF image
1259 *
1260 * @param contentUri Content URI of the PNG image to be sent
1261 * @param imageDescription Description of the PNG image to be sent
1262 * @param emoticonId EmoticonsId
1263 */
1264
1265 // content://media/external/images/media/49428
1266 public void commitEmoticon(Uri contentUri, String imageDescription, int emoticonId) {
1267 CommonUtils.hideSoftKeyBoard(SoftKeyboard.this, rvEmoticonsParent);
1268
1269 //After Hiding keyboard stats is shared
1270 callToStatsApi(new StatsRequestModel(emoticonId));
1271
1272 try {
1273 InputContentInfoCompat inputContentInfo = new InputContentInfoCompat(
1274 contentUri,
1275 new ClipDescription(imageDescription, new String[]{"image/png"}),
1276 null
1277 );
1278 InputConnection inputConnection = getCurrentInputConnection();
1279 EditorInfo editorInfo = getCurrentInputEditorInfo();
1280 int flags = 0;
1281 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
1282 flags |= InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION;
1283 } else {
1284
1285 // On API 24 and prior devices, we cannot rely on
1286 // InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION. You as an IME author
1287 // need to decide what access control is needed (or not needed) for content URIs that
1288 // you are going to expose. This sample uses Context.grantUriPermission(), but you can
1289 // implement your own mechanism that satisfies your own requirements.
1290 int flag = 0;
1291 try {
1292 grantUriPermission(
1293 editorInfo.packageName, contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
1294 } catch (Exception e) {
1295 Log.e(TAG, "grantUriPermission failed packageName=" + editorInfo.packageName
1296 + " contentUri=" + contentUri, e);
1297 }
1298 }
1299 InputConnectionCompat.commitContent(
1300 inputConnection, editorInfo, inputContentInfo, flags, null);
1301 } catch (Exception e) {
1302
1303 Log.v("COMMIT", e.getLocalizedMessage());
1304
1305 }
1306
1307
1308 }
1309
1310 /**
1311 * Helper to update the shift state of our keyboard based on the initial
1312 * editor state.
1313 */
1314 private void updateShiftKeyState(EditorInfo attr) {
1315 if (attr != null
1316 && mInputView != null && mQwertyKeyboard == mInputView.getKeyboard()) {
1317 int caps = 0;
1318 EditorInfo ei = getCurrentInputEditorInfo();
1319 if (ei != null && ei.inputType != InputType.TYPE_NULL) {
1320 caps = getCurrentInputConnection().getCursorCapsMode(attr.inputType);
1321 }
1322 mInputView.setShifted(mCapsLock || caps != 0);
1323 }
1324 }
1325
1326 /**
1327 * Helper to determine if a given character code is alphabetic.
1328 */
1329 private boolean isAlphabet(int code) {
1330 if (Character.isLetter(code)) {
1331 return true;
1332 } else {
1333 return false;
1334 }
1335 }
1336
1337 // Implementation of KeyboardViewListener
1338
1339 /**
1340 * Helper to send a key down / key up pair to the current editor.
1341 */
1342 private void keyDownUp(int keyEventCode) {
1343 getCurrentInputConnection().sendKeyEvent(
1344 new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode));
1345 getCurrentInputConnection().sendKeyEvent(
1346 new KeyEvent(KeyEvent.ACTION_UP, keyEventCode));
1347 }
1348
1349 /**
1350 * for vibration.
1351 */
1352 private void setVibrator() {
1353 if (Build.VERSION.SDK_INT >= 26) {
1354 ((Vibrator) getSystemService(VIBRATOR_SERVICE)).vibrate(VibrationEffect.createOneShot(50, VibrationEffect.DEFAULT_AMPLITUDE));
1355 } else {
1356 ((Vibrator) getSystemService(VIBRATOR_SERVICE)).vibrate(50);
1357 }
1358 }
1359
1360 /**
1361 * Helper to send a character to the editor as raw key events.
1362 */
1363 private void sendKey(int keyCode) {
1364 switch (keyCode) {
1365 case '\n':
1366 keyDownUp(KeyEvent.KEYCODE_ENTER);
1367 break;
1368 default:
1369 if (keyCode >= '0' && keyCode <= '9') {
1370 keyDownUp(keyCode - '0' + KeyEvent.KEYCODE_0);
1371 } else {
1372 getCurrentInputConnection().commitText(String.valueOf((char) keyCode), 1);
1373 }
1374 break;
1375 }
1376 }
1377
1378 public void onKey(int primaryCode, int[] keyCodes) {
1379 Log.d("Test", "KEYCODE: " + primaryCode);
1380 if (isWordSeparator(primaryCode)) {
1381 // Handle separator
1382 if (mComposing.length() > 0) {
1383 commitTyped(getCurrentInputConnection());
1384 }
1385 sendKey(primaryCode);
1386 updateShiftKeyState(getCurrentInputEditorInfo());
1387 } else if (primaryCode == Keyboard.KEYCODE_DELETE) {
1388 handleBackspace();
1389 } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
1390 handleShift();
1391 } else if (primaryCode == Keyboard.KEYCODE_CANCEL) {
1392 handleClose();
1393 return;
1394 } else if (primaryCode == LatinKeyboardView.KEYCODE_LANGUAGE_SWITCH) {
1395 handleLanguageSwitch();
1396 return;
1397 } else if (primaryCode == LatinKeyboardView.KEYCODE_OPTIONS) {
1398 // Show a menu or somethin'
1399 } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE
1400 && mInputView != null) {
1401 Keyboard current = mInputView.getKeyboard();
1402 if (current == mSymbolsKeyboard || current == mSymbolsShiftedKeyboard) {
1403 setLatinKeyboard(mQwertyKeyboard);
1404 } else {
1405 setLatinKeyboard(mSymbolsKeyboard);
1406 mSymbolsKeyboard.setShifted(false);
1407 }
1408 } else {
1409 handleCharacter(primaryCode, keyCodes);
1410 }
1411 }
1412
1413 public void onText(CharSequence text) {
1414 InputConnection ic = getCurrentInputConnection();
1415 if (ic == null) return;
1416 ic.beginBatchEdit();
1417 if (mComposing.length() > 0) {
1418 commitTyped(ic);
1419 }
1420 ic.commitText(text, 0);
1421 ic.endBatchEdit();
1422 updateShiftKeyState(getCurrentInputEditorInfo());
1423 }
1424
1425 /**
1426 * Update the list of available candidates from the current composing
1427 * text. This will need to be filled in by however you are determining
1428 * candidates.
1429 */
1430 private void updateCandidates() {
1431 if (!mCompletionOn) {
1432 if (mComposing.length() > 0) {
1433 ArrayList<String> list = new ArrayList<String>();
1434 list.add(mComposing.toString());
1435 //Log.d("SoftKeyboard", "REQUESTING: " + mComposing.toString());
1436 if (mScs != null) {
1437 mScs.getSentenceSuggestions(new TextInfo[]{new TextInfo(mComposing.toString())}, 5);
1438 setSuggestions(list, true, true, mComposing.toString());
1439 }
1440 } else {
1441 setSuggestions(null, false, false, mComposing.toString());
1442 }
1443 }
1444 }
1445
1446
1447 public void getPredictor() {
1448 if (mSuggestions == null) {
1449 mSuggestions = new ArrayList<>();
1450 } else {
1451 mSuggestions.clear();
1452 }
1453 currentInputString = mComposing.toString();
1454
1455 if (TextUtils.isEmpty(currentInputString)) {//predict next word
1456 predictor.predictNextWordAsync(currentLanguage, 5, currentInputString, new OnPredictListener() {
1457 @Override
1458 public void onPredict(List<String> words) {
1459 if (mSuggestions != null && words != null) {
1460 mSuggestions.addAll(words);
1461 setSuggestions(mSuggestions, true, true, "");
1462 }
1463 }
1464 });
1465 } else {//predict current word
1466 String[] words = currentInputString.split("\\s+");
1467 String lastWord = words[words.length - 1];
1468 predictor.predictCurrentWordAsync(currentLanguage, 5, lastWord, new OnPredictListener() {
1469 @Override
1470 public void onPredict(List<String> words) {
1471// currentPredictions.setText(words.toString());
1472 if (mSuggestions != null && words != null) {
1473 mSuggestions.addAll(words);
1474 setSuggestions(mSuggestions, true, true, "");
1475 }
1476 }
1477 });
1478 }
1479
1480 //Log.d(TAG, "mSuggestions:" + Arrays.toString(mSuggestions.toArray()));
1481 }
1482
1483 public void setSuggestions(List<String> suggestions, boolean completions,
1484 boolean typedWordValid, String inCompleteString) {
1485
1486
1487 if (suggestions != null && suggestions.size() > 0) {
1488 setCandidatesViewShown(true);
1489 } else if (isExtractViewShown()) {
1490 setCandidatesViewShown(true);
1491 }
1492
1493 if (suggestions != null && suggestions.size() == 1) {
1494 //suggestionSize = 0;
1495 suggestions.clear();
1496 Log.d(TAG, "suggestions: " + suggestions.size());
1497 }
1498
1499 mSuggestions = suggestions;
1500
1501 if (mCandidateView != null && mSuggestions != null && mSuggestions.size() != 0) {
1502 mCandidateView.setSuggestions(mSuggestions, completions, typedWordValid);
1503 }
1504
1505
1506 }
1507
1508 private void handleBackspace() {
1509 final int length = mComposing.length();
1510 if (length > 1) {
1511 mComposing.delete(length - 1, length);
1512 getCurrentInputConnection().setComposingText(mComposing, 1);
1513 updateCandidates();
1514 } else if (length > 0) {
1515 mComposing.setLength(0);
1516 getCurrentInputConnection().commitText("", 0);
1517 updateCandidates();
1518 } else {
1519 keyDownUp(KeyEvent.KEYCODE_DEL);
1520 }
1521 updateShiftKeyState(getCurrentInputEditorInfo());
1522 }
1523
1524 private void handleShift() {
1525 if (mInputView == null) {
1526 return;
1527 }
1528
1529 Keyboard currentKeyboard = mInputView.getKeyboard();
1530 if (mQwertyKeyboard == currentKeyboard) {
1531 // Alphabet keyboard
1532 checkToggleCapsLock();
1533 mInputView.setShifted(mCapsLock || !mInputView.isShifted());
1534 } else if (currentKeyboard == mSymbolsKeyboard) {
1535 mSymbolsKeyboard.setShifted(true);
1536 setLatinKeyboard(mSymbolsShiftedKeyboard);
1537 mSymbolsShiftedKeyboard.setShifted(true);
1538 } else if (currentKeyboard == mSymbolsShiftedKeyboard) {
1539 mSymbolsShiftedKeyboard.setShifted(false);
1540 setLatinKeyboard(mSymbolsKeyboard);
1541 mSymbolsKeyboard.setShifted(false);
1542 }
1543 }
1544
1545 private void handleCharacter(int primaryCode, int[] keyCodes) {
1546 if (isInputViewShown()) {
1547 if (mInputView.isShifted()) {
1548 primaryCode = Character.toUpperCase(primaryCode);
1549 }
1550 }
1551 if (mPredictionOn) {
1552 mComposing.append((char) primaryCode);
1553 getCurrentInputConnection().setComposingText(mComposing, 1);
1554 updateShiftKeyState(getCurrentInputEditorInfo());
1555 updateCandidates();
1556 } else {
1557 getCurrentInputConnection().commitText(
1558 String.valueOf((char) primaryCode), 1);
1559 }
1560 }
1561
1562 private void handleClose() {
1563 commitTyped(getCurrentInputConnection());
1564 requestHideSelf(0);
1565 mInputView.closing();
1566 }
1567
1568 private IBinder getToken() {
1569 final Dialog dialog = getWindow();
1570 if (dialog == null) {
1571 return null;
1572 }
1573 final Window window = dialog.getWindow();
1574 if (window == null) {
1575 return null;
1576 }
1577 return window.getAttributes().token;
1578 }
1579
1580 private void handleLanguageSwitch() {
1581 mInputMethodManager.switchToNextInputMethod(getToken(), false /* onlyCurrentIme */);
1582 }
1583
1584 private void checkToggleCapsLock() {
1585 long now = System.currentTimeMillis();
1586 if (mLastShiftTime + 800 > now) {
1587 mCapsLock = !mCapsLock;
1588 mLastShiftTime = 0;
1589 } else {
1590 mLastShiftTime = now;
1591 }
1592 }
1593
1594 private String getWordSeparators() {
1595 return mWordSeparators;
1596 }
1597
1598 public boolean isWordSeparator(int code) {
1599 String separators = getWordSeparators();
1600 return separators.contains(String.valueOf((char) code));
1601 }
1602
1603 public void pickDefaultCandidate() {
1604 pickSuggestionManually(0);
1605 }
1606
1607 public void pickSuggestionManually(int index) {
1608 if (mCompletionOn && mCompletions != null && index >= 0
1609 && index < mCompletions.length) {
1610 CompletionInfo ci = mCompletions[index];
1611 getCurrentInputConnection().commitCompletion(ci);
1612 if (mCandidateView != null) {
1613 mCandidateView.clear();
1614 }
1615 updateShiftKeyState(getCurrentInputEditorInfo());
1616 } else if (mComposing.length() > 0) {
1617
1618 if (mPredictionOn && mSuggestions != null && index >= 0) {
1619 mComposing.replace(0, mComposing.length(), mSuggestions.get(index));
1620 }
1621 commitTyped(getCurrentInputConnection());
1622
1623 }
1624 }
1625
1626 public void swipeRight() {
1627 Log.d("SoftKeyboard", "Swipe right");
1628 if (mCompletionOn || mPredictionOn) {
1629 pickDefaultCandidate();
1630 }
1631 }
1632
1633 public void swipeLeft() {
1634 Log.d("SoftKeyboard", "Swipe left");
1635 handleBackspace();
1636 }
1637
1638 public void swipeDown() {
1639 handleClose();
1640 }
1641
1642 public void swipeUp() {
1643 }
1644
1645 public void onPress(int primaryCode) {
1646
1647 }
1648
1649 public void onRelease(int primaryCode) {
1650
1651 }
1652
1653 /**
1654 * http://www.tutorialspoint.com/android/android_spelling_checker.htm
1655 *
1656 * @param results results
1657 */
1658 @Override
1659 public void onGetSuggestions(SuggestionsInfo[] results) {
1660 final StringBuilder sb = new StringBuilder();
1661
1662 for (int i = 0; i < results.length; ++i) {
1663 // Returned suggestions are contained in SuggestionsInfo
1664 final int len = results[i].getSuggestionsCount();
1665 sb.append('\n');
1666
1667 for (int j = 0; j < len; ++j) {
1668 sb.append("," + results[i].getSuggestionAt(j));
1669 }
1670
1671 sb.append(" (" + len + ")");
1672 }
1673
1674 Log.d("SoftKeyboard", "SUGGESTIONS2: " + sb.toString());
1675 }
1676
1677 private void dumpSuggestionsInfoInternal(
1678 final List<String> sb, final SuggestionsInfo si, final int length, final int offset) {
1679 // Returned suggestions are contained in SuggestionsInfo
1680 final int len = si.getSuggestionsCount();
1681 Log.d(TAG, "EMPTY SR: " + len);
1682 for (int j = 0; j < len; ++j) {
1683 Log.d(TAG, "EMPTY SR: " + j + "->>" + si.getSuggestionAt(j).trim().isEmpty());
1684 //if (!si.getSuggestionAt(j).trim().isEmpty()) { //added to check empty text
1685 sb.add(si.getSuggestionAt(j));
1686 //}
1687 }
1688 }
1689
1690
1691 @Override
1692 public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results) {
1693 Log.d("SoftKeyboard", "onGetSentenceSuggestions");
1694 final List<String> sb = new ArrayList<>();
1695 for (int i = 0; i < results.length; ++i) {
1696 final SentenceSuggestionsInfo ssi = results[i];
1697 for (int j = 0; j < ssi.getSuggestionsCount(); ++j) {
1698 // ssi.getLengthAt(j) -> number of characters typed
1699 dumpSuggestionsInfoInternal(
1700 sb, ssi.getSuggestionsInfoAt(j), ssi.getOffsetAt(j), ssi.getLengthAt(j));
1701 }
1702 }
1703 suggestionSize = sb.size();
1704 Log.d("SoftKeyboard", "SUGGESTIONS SIZE: " + suggestionSize);
1705 Log.d("SoftKeyboard", "SUGGESTIONS: " + sb.toString());
1706 //setSuggestions(sb, true, true, "");
1707 getPredictor();
1708 }
1709
1710 @Override
1711 public void onFEmaleEmoticonClick(EmoticonFinalData emoticonFinalData, int position) {
1712
1713 }
1714
1715 private Uri getUriFromPath(String filePath) {
1716 long photoId;
1717 Uri photoUri = MediaStore.Images.Media.getContentUri("external");
1718
1719 String[] projection = {MediaStore.Images.ImageColumns._ID};
1720 // TODO This will break if we have no matching item in the MediaStore.
1721 Cursor cursor = getContentResolver().query(photoUri, projection, MediaStore.Images.ImageColumns.DATA + " LIKE ?", new String[]{filePath}, null);
1722 cursor.moveToFirst();
1723
1724 int columnIndex = cursor.getColumnIndex(projection[0]);
1725 photoId = cursor.getLong(columnIndex);
1726
1727 cursor.close();
1728 return Uri.parse(photoUri.toString() + "/" + photoId);
1729 }
1730
1731 @Override
1732 public void onItemClick(EmoticonFinalData emoticonFinalData, int position) {
1733// CursorLoader cursorLoader = new CursorLoader(getBaseContext(), CONTENT_URI,
1734// new String[]{"IMAGETITLE", "IMAGEURL", "IMAGEDESC"}, "IMAGEDESC=?", new String[]
1735// {emoticon.getId().toString()}, null);
1736// Cursor c = cursorLoader.loadInBackground();
1737// Log.v("soft", c.getColumnName(position));
1738
1739// adapter = new SimpleCursorAdapter(getBaseContext(),
1740// R.layout.list_layout,
1741// null,
1742// new String[] { "IMAGETITLE", "IMAGEURL", "IMAGEDESC"},
1743// new int[] { R.id.imgTitle , R.id.imgUrl, R.id.imgDesc }, 0);
1744
1745
1746 }
1747
1748 //----------------------------------------------------------- db part -----------------------------------------------//
1749 private void refreshValuesFromContentProvider() {
1750 CursorLoader cursorLoader = new CursorLoader(getBaseContext(), CONTENT_URI,
1751 null, null, null, null);
1752 Cursor c = cursorLoader.loadInBackground();
1753 adapter = new SimpleCursorAdapter(getBaseContext(),
1754 R.layout.list_layout,
1755 null,
1756 new String[]{"IMAGETITLE", "IMAGEURL", "IMAGEDESC"},
1757 new int[]{R.id.imgTitle, R.id.imgUrl, R.id.imgDesc}, 0);
1758
1759 listView.setAdapter(adapter);
1760 final String s = c.getColumnName(0);
1761// Toast.makeText(this, "col 0" + s, Toast.LENGTH_SHORT).show();
1762 adapter.swapCursor(c);
1763 }
1764
1765 private void callToStatsApi(StatsRequestModel statsRequestModel) {
1766 if (NetworkUtils.isNetworkAvailable(this)) {
1767 final StatsApi statsApi = new StatsApi(this, this);
1768 statsApi.postStats(statsRequestModel);
1769 } else {
1770 Log.d(TAG, "No internet");
1771 //Toast.makeText(this, "No internet", Toast.LENGTH_SHORT).show();
1772 }
1773 }
1774
1775 @Override
1776 public void onStatsFailure(String message) {
1777
1778 }
1779
1780 @Override
1781 public void onStatsExpired() {
1782
1783 }
1784
1785 @Override
1786 public void onStatsSuccess(StatsResponseModel response) {
1787 if (response.getSuccess()) {
1788 Log.d(TAG, "Stats Updated to Server");
1789 }
1790 }
1791
1792 private class GetContentURI extends AsyncTask<String, Void, Void> {
1793
1794
1795 private File fileFinal = null;
1796 private String imageUrl = "";
1797
1798 public GetContentURI(String url) {
1799 this.imageUrl = url;
1800 }
1801
1802 @Override
1803 protected Void doInBackground(String... strings) {
1804
1805 try {
1806 final File direct = new File(Environment.getExternalStorageDirectory() + getString(R.string.label_sdcard_file_name));
1807
1808 if (!direct.exists()) {
1809 final File newFile = new File(Environment.getExternalStorageDirectory() + getString(R.string.label_sdcard_file_name));
1810 newFile.mkdirs();
1811 }
1812
1813 final File file = new File(Environment.getExternalStorageDirectory() + getString(R.string.label_sdcard_file_name), getString(R.string.app_name) +
1814 System.currentTimeMillis() + getString(R.string.label_image_type));
1815 if (file.exists()) {
1816 file.delete();
1817 }
1818 URL url = new URL(imageUrl);
1819 InputStream is = url.openStream();
1820 OutputStream os = new FileOutputStream(file);
1821
1822 byte[] b = new byte[2048];
1823 int length;
1824
1825 while ((length = is.read(b)) != -1) {
1826 os.write(b, 0, length);
1827 }
1828
1829 is.close();
1830 os.close();
1831 fileFinal = file;
1832
1833
1834 } catch (IOException e) {
1835 e.printStackTrace();
1836 }
1837
1838 return null;
1839 }
1840
1841 @Override
1842 protected void onPreExecute() {
1843 super.onPreExecute();
1844
1845 }
1846
1847
1848 @Override
1849 protected void onPostExecute(Void aVoid) {
1850 super.onPostExecute(aVoid);
1851// final Uri uriFinal = getUriFromPath(fileFinal.getAbsolutePath());
1852 final Uri uri = getImageContentUri(SoftKeyboard.this, fileFinal);
1853 ivDummy.setImageURI(uri);
1854 dummyURI = uri;
1855// Log.v(TAG, String.valueOf(uriFinal));
1856 }
1857
1858 }
1859}