Saturday, December 30, 2017

Agera Repository


In our previous blog post we have learnt about Agera, about Reactive programming  and Sample code of Hello World Example using Agera - Functional Reactive Programming for Android recommended by Google. In Hello World Example learn about Observable, Updatable, Supplier and Receiver

In this blog I am going to introduce Repository.


What is the Repository ??

The most important concept in Agera is the Repository. Repositories receive, supply, and store data and emit updates. The interfaces Observable, Supplier and Receiver are combined into two types of repositories:


InterfaceObservableSupplierReceiver
Repository☑☑☐
MutableRepository☑☑☑


In our hello world code, you could replace
implements Observable, Supplier<String>, Receiver<String>
with
 implements MutableRepository<String>
but Agera provides a Repository factory, so remove the MyDataSupplier class altogether and replace
  MyDataSupplier myDataSupplier = new MyDataSupplier();
with
 MutableRepository<String> mStringRepo = Repositories.mutableRepository("Initial value by Agera with Repository");
mutableRepository() creates a repository similar to our previous implementation, but that is thread-safe and has a more sophisticated update dispatcher, so let's use that from now on.
Also, remove the updatables (with removeUpdatable()) when you know you're done with them. In our example this is not needed but it is a good practice: it avoids potential leaks and prevents updating destroyed views. The class is now much shorter:
 public class JavaMainActivity extends AppCompatActivity {
     //    MyDataSupplier myDataSupplier = new MyDataSupplier();
     //    Updatable updatable;
     private MutableRepository<String> mStringRepo;
     private Updatable mLoggerUpdatable;


     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);

        mStringRepo = Repositories.mutableRepository("Initial value by Agera with Repository");

       final TextView textView = findViewById(R.id.textView);

          // Create an Updatable
          //        updatable = new Updatable() {
          //            @Override
          //            public void update() {
          //                Log.d("AGERA", myDataSupplier.get());
          //                textView.setText(myDataSupplier.get());
          //            }
          //        };
          //        myDataSupplier.addUpdatable(updatable);

          //        myDataSupplier.accept("Hello Agera!");


          // Create an Updatable by Respository
      mLoggerUpdatable = () -> {
          Log.d("AGERA", mStringRepo.get());
          textView.setText(mStringRepo.get());
      };
     }

      @Override
      protected void onStart() {
          super.onStart();
          mStringRepo.addUpdatable(mLoggerUpdatable);

          // Change the repository's value
          mStringRepo.accept("Hello World by Agera with Repository");
      }

    @Override
     protected void onStop() {
        mStringRepo.removeUpdatable(mLoggerUpdatable);
       super.onStop();
     }
 }

In summary:

Agera uses very simple interfaces you should be aware of:
 Observable, Updatable, Supplier and Receiver. These are combined in the Repository and MutableRepository interfaces.
  • Agera provides a factory of implementations of these simple Repositories: Repositories.mutableRepository(T)and Repositories.repository(T) for immutable repositories.
Source code for this can be found here Enjoy !!!!


Contact - Let's connect to each other


Thursday, December 14, 2017

Agera - Functional Reactive Programming for Android

What is Agera?

Agera is a super lightweight Android library that helps prepare data for consumption by the Android application components (such as Activities), or objects therein (such as Views), that have life-cycles in one form or another.
It introduces a flavor of functional reactive programming, facilitates clear separation of the when, where and what factors of a data processing flow, and enables describing such a complex and asynchronous flow with a single expression, in near natural language.

second question comes to any mind is 

What do we mean by reactive?


Reactive programming is a paradigm related to how changes are propagated in a program. A good example is a spreadsheet: cells contain formulas that depend on other cells' values. When one of these values are changed, there's no need to manually update the resulting values; the changes are propagated for you. Agera brings a reactive flavor to Android using an observer pattern.

Hello World Example

Lets start with simplest example of programming world, that is Hello World Example.
But to learn how to code for "Hello World", we need to learn basic components of Agera.

The foundation of Agera is a set of very simple interfaces including: Observable, Updatable, Supplier and Receiver:

Observable.java
public interface Observable {

  void addUpdatable(Updatable updatable);

  void removeUpdatable(Updatable updatable);
}


Updatable.java

public interface Updatable {

  void update();
}


Supplier.java

public interface Supplier<T> {

  T get();
}

Receiver.java

public interface Receiver<T> {

  void accept(T value);
}


As you can see, these four interfaces are very simple. This is what they're responsible for:

  • Observable => Something that can be observed for changes and stores a list of updatable objects. When a change occurs, the updatables are poked
  • Updatable => Called when an event has occurred. Its update() method will be called when the class it observes changes, but can also be called manually to force an update.
  • Supplier => Something that supplies data when the get() method is called. In this case, "Data" can be anything.
  • Receiver => Something that can receive (and normally store) a value send to it via accept().
lets see how to use them in our code.
I have already written Hello World Example on Github

All the best !!! Happy Coding !!!

Next Step is to learn Repository..

Repository => The most important concept in Agera is the Repository. Repositories receive, supply, and store data and emit updates. The interfaces Observable, Supplier and Receiver are combined into two types of repositories:
  Repository can replace Observable and Supplier
  MutableRepository can replace Observable, Supplier and Receiver
A complete blogpost is coming soon on Repository...!!

let's connect to learn together







Wednesday, March 22, 2017

Android O saves phone's battery

Top Android O features:

1. Better battery life:

The previous few Android refreshes Doze, Doze in a hurry went for enhancing battery life. With Android O, Google is further clipping down on unpredictable applications eating the battery out of sight.
Android O places specific limits on implicit broadcasts (signals sent by an application for other apps or activities to act upon), location updates and background services. All these happen automatically in the background, without users having to manage anything on their own.
This will prevent errant applications which you haven’t used in a long time from sapping your battery life whilst implementing background processes.

2. Managing/Grouping Notifications

O introduces notification channels that allow you to create a user-customizable channel for each type of notification you want to display. The user interface refers to notification channels as notification categories. To learn how to implement notification channels, check the Notification Channels guide by official website.
Notifications can be segmented into various different channels like sports news, text messages, music applications and so on and users can control each channel separately. The notification shade will also group notifications by channel, making it much easier to glance through relevant notifications. Users can also block or snooze a whole channel in one go if they wish.

3. AutoFill

While AutoFill in Android exists in certain applications like Messages and Chrome, the feature is app-specific and is not a part of the whole OS.
Android O makes filling out forms, such as login and credit card forms, easier with the introduction of the Autofill Framework. Existing and new apps work with Autofill Framework after the user opts in to autofill.

4. Picture-in-Picture mode

Android O allows activities to launch in picture-in-picture (PIP) mode. PIP is a special type of multi-window mode mostly used for video playback. PIP mode is already available for Android TV; Android O makes the feature available on other Android devices.
Developers can specify which aspect ratio they want for their application and can even set custom interactions on the PIP window. This feature is already available on devices running Android TV.

5. Audio improvements

With Android O, Google is presenting a few new components went for audiophiles. Android O carries with it bolster for amazing sound codecs, for example, LDAC.
Moreover, Google is additionally presenting AAudio — another local API for applications requiring support for elite, low-idleness sound.

6. Adaptive Icons

Adaptive icons will be supported in the launcher, device settings, the app overview screen and shortcuts.
Android O introduces adaptive launcher icons. Adaptive icons support visual effects, and can display a variety of shapes across different device models. To learn how to create adaptive icons, see the Adaptive Icons preview feature guide.

7. Better keyboard navigation

With Chromebooks now supporting Android applications, Google has introduced a new model for keyboard navigation in Android O.
Specifically, Android O brings with it a better way to navigate around Android using the arrow and tab keys on the keyboard.

8. Wide-gamut color for apps

Android developers of imaging apps can now take advantage of new devices that have a wide-gamut color capable display. To display wide gamut images, apps will need to enable a flag in their manifest (per activity) and load bitmaps with an embedded wide color profile (AdobeRGB, Pro Photo RGB, DCI-P3, etc.).

9. Support for third-party calling apps

Android O supports third-party calling apps natively. Google has introduced a new feature called ‘Telecom framework’, which allows for third-party calling applications to work with each other and with carriers.

10. WebView APIs

Android O provides several APIs to help you manage the WebView objects that display web content in your app. These APIs, which improve your app's stability and security, include the following:
·         Version API
·         Google SafeBrowsing API
·         Termination Handle API
·         Renderer Importance API
Android O also brings with it optimisations for new runtimes for better stability and performance in applications designed specifically for Android O

Monday, May 2, 2016

Developing your own keyboard

Writing/ Developing your own keyboard is easy task,

follow the steps given below and you will have your own keyboard in your cellpahone.

1. Create a normal Android Project using Android Studio.

2. Edit Application tab in Manifest;
    Add the following lines into Application tab

<service
    android:name=".utils.SoftKeyboard"
    android:permission="android.permission.BIND_INPUT_METHOD">
    <intent-filter>
        <action android:name="android.view.InputMethod" />
    </intent-filter>
    <meta-data
        android:name="android.view.im"
        android:resource="@xml/method" />
</service>

<activity
    android:name=".activities.ImePreferences"
    android:label="@string/settings_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
    </intent-filter>
</activity>

3. Create a folder "xml" in res and Create method.xml

paste following line to method.xml

<input-method xmlns:android="http://schemas.android.com/apk/res/android"
    android:settingsActivity="com.example.android.softkeyboard.ImePreferences"
    android:supportsSwitchingToNextInputMethod="true">
    <subtype
        android:imeSubtypeLocale="en_US"
        android:imeSubtypeMode="keyboard"
        android:label="Ankit" />
    <subtype
        android:imeSubtypeLocale="en_GB"
        android:imeSubtypeMode="keyboard"
        android:label="Ankit" />
</input-method>

4. Create input keyboard layout input.xml in res/layout

<?xml version="1.0" encoding="utf-8"?>
<com.divyankit.keyboard.utils.LatinKeyboardView
xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/keyboard"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true" />



5.  Java Code for LatinKeyboardView is here

LatinKeyboardView.java

public class LatinKeyboardView extends KeyboardView {
    static final int KEYCODE_OPTIONS = -100;
    static final int KEYCODE_LANGUAGE_SWITCH = -101;
    static final int KEYCODE_API = -600;

    public LatinKeyboardView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public LatinKeyboardView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override    protected boolean onLongPress(Key key) {
        if (key.codes[0] == Keyboard.KEYCODE_CANCEL) {
            getOnKeyboardActionListener().onKey(KEYCODE_OPTIONS, null);
            return true;
        } else {
            return super.onLongPress(key);
        }
    }

    void setSubtypeOnSpaceKey(final InputMethodSubtype subtype) {
        final LatinKeyboard keyboard = (LatinKeyboard) getKeyboard();
         
         // keyboard.setSpaceIcon(getResources().getDrawable(subtype.getIconResId()));    
         // keyboard.setShifted(true);       
        
        invalidateAllKeys();
    }
}


6. Java Code for LatinKeyboard is here
LtinKeyboard.java
public class LatinKeyboard extends Keyboard {
    private Key mEnterKey;
    private Key mSpaceKey;
    
/**
* Stores the current state of the mode change key.
 Its width will be dynamically updated to    
 * match the region of {@link #mModeChangeKey} when {@link #mModeChangeKey} 
becomes invisible.*/

    private Key mModeChangeKey;
/**
* Stores the current state of the language switch key (a.k.a. globe key). This should be     
* visible while {@link InputMethodManager#shouldOfferSwitchingToNextInputMethod(IBinder)}  
   * returns true. When this key becomes invisible, its width will be shrunk to zero.*/
    private Key mLanguageSwitchKey;
    /**
* Stores the size and other information of {@link #mModeChangeKey} when   
* {@link #mLanguageSwitchKey} is visible. This should be immutable and will be used only as a
* reference size when the visibility of {@link #mLanguageSwitchKey} is changed.*/
    private Key mSavedModeChangeKey;
/**
* Stores the size and other information of {@link #mLanguageSwitchKey} when it is visible.
* This should be immutable and will be used only as a reference size when the visibility of 
* {@link #mLanguageSwitchKey} is changed.*/
    private Key mSavedLanguageSwitchKey;

    public LatinKeyboard(Context context, int xmlLayoutResId) {
        super(context, xmlLayoutResId);
    }

    public LatinKeyboard(Context context, int layoutTemplateResId,
                         CharSequence characters, int columns, int horizontalPadding) {
        super(context, layoutTemplateResId, characters, columns, horizontalPadding);
    }

    @Override
    protected Key createKeyFromXml(Resources res, Row parent, int x, int y,
     XmlResourceParser parser) {
        Key key = new LatinKey(res, parent, x, y, parser);
        if (key.codes[0] == 10) {
            mEnterKey = key;
        } else if (key.codes[0] == ' ') {
            mSpaceKey = key;
        } else if (key.codes[0] == Keyboard.KEYCODE_MODE_CHANGE) {
            mModeChangeKey = key;
            mSavedModeChangeKey = new LatinKey(res, parent, x, y, parser);
        } else if (key.codes[0] == LatinKeyboardView.KEYCODE_LANGUAGE_SWITCH) {
            mLanguageSwitchKey = key;
            mSavedLanguageSwitchKey = new LatinKey(res, parent, x, y, parser);
        }
        return key;
    }

/**
* Dynamically change the visibility of the language switch key (a.k.a. globe key). 
* * @param visible True if the language switch key should be visible.     */

void setLanguageSwitchKeyVisibility(boolean visible) {
        if (visible) {
      // The language switch key should be visible. Restore the size of the mode change key  
      // and language switch key using the saved layout.           

 mModeChangeKey.width = mSavedModeChangeKey.width;
            mModeChangeKey.x = mSavedModeChangeKey.x;
            mLanguageSwitchKey.width = mSavedLanguageSwitchKey.width;
            mLanguageSwitchKey.icon = mSavedLanguageSwitchKey.icon;
            mLanguageSwitchKey.iconPreview = mSavedLanguageSwitchKey.iconPreview;
        } else {
      // The language switch key should be hidden. Change the width of the mode change key 
      // to fill the space of the language key so that the user will not see any strange gap.         
            mModeChangeKey.width = mSavedModeChangeKey.width + mSavedLanguageSwitchKey.width;
            mLanguageSwitchKey.width = 0;
            mLanguageSwitchKey.icon = null;
            mLanguageSwitchKey.iconPreview = null;
        }
    }

    /**
* This looks at the ime options given by the current editor, to set the   
* appropriate label on the keyboard's enter key (if it has one).     */ 

    void setImeOptions(Resources res, int options) {
        if (mEnterKey == null) {
            return;
        }
        switch (options & (EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION)) {
            case EditorInfo.IME_ACTION_GO:
                mEnterKey.iconPreview = null;
                mEnterKey.icon = null;
                mEnterKey.label = res.getText(R.string.label_go_key);
                break;
            case EditorInfo.IME_ACTION_NEXT:
                mEnterKey.iconPreview = null;
                mEnterKey.icon = null;
                mEnterKey.label = res.getText(R.string.label_next_key);
                break;
            case EditorInfo.IME_ACTION_SEARCH:
                mEnterKey.icon = res.getDrawable(R.drawable.sym_keyboard_search);
                mEnterKey.label = null;
                break;
            case EditorInfo.IME_ACTION_SEND:
                mEnterKey.iconPreview = null;
                mEnterKey.icon = null;
                mEnterKey.label = res.getText(R.string.label_send_key);
                break;
            default:
                mEnterKey.icon = res.getDrawable(R.drawable.sym_keyboard_return);
                mEnterKey.label = null;
                break;
        }
    }
    void setSpaceIcon(final Drawable icon) {
        if (mSpaceKey != null) {
            mSpaceKey.icon = icon;
        }
    }
    static class LatinKey extends Key {

        public LatinKey(Resources res, Row parent, int x, int y,
                        XmlResourceParser parser) {
            super(res, parent, x, y, parser);
        }
        /**
* Overriding this method so that we can reduce the target area for the key that
* closes the keyboard.         */   
     @Override
        public boolean isInside(int x, int y) {
            return super.isInside(x, codes[0] == KEYCODE_CANCEL ? y - 10 : y);
        }
    }
}

5. Define the Keyboard Keys: 

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:horizontalGap="0px"
    android:keyHeight="@dimen/key_height"
    android:keyWidth="10%p"
    android:verticalGap="0px">
    <Row>
        <Key
            android:codes="113"
            android:keyEdgeFlags="left"
            android:keyLabel="q" />
        <Key
            android:codes="119"
            android:keyLabel="w" />
        <Key
            android:codes="101"
            android:keyLabel="e" />
        <Key
            android:codes="114"
            android:keyLabel="r" />
        <Key
            android:codes="116"
            android:keyLabel="t" />
        <Key
            android:codes="121"
            android:keyLabel="y" />
        <Key
            android:codes="117"
            android:keyLabel="u" />
        <Key
            android:codes="105"
            android:keyLabel="i" />
        <Key
            android:codes="111"
            android:keyLabel="o" />
        <Key
            android:codes="112"
            android:keyEdgeFlags="right"
            android:keyLabel="p" />
    </Row>

    <Row>
        <Key
            android:codes="97"
            android:horizontalGap="5%p"
            android:keyEdgeFlags="left"
            android:keyLabel="a" />
        <Key
            android:codes="115"
            android:keyLabel="s" />
        <Key
            android:codes="100"
            android:keyLabel="d" />
        <Key
            android:codes="102"
            android:keyLabel="f" />
        <Key
            android:codes="103"
            android:keyLabel="g" />
        <Key
            android:codes="104"
            android:keyLabel="h" />
        <Key
            android:codes="106"
            android:keyLabel="j" />
        <Key
            android:codes="107"
            android:keyLabel="k" />
        <Key
            android:codes="108"
            android:keyEdgeFlags="right"
            android:keyLabel="l" />
    </Row>

    <Row>
        <Key
            android:codes="-1"
            android:isModifier="true"
            android:isSticky="true"
            android:keyEdgeFlags="left"
            android:keyIcon="@drawable/sym_keyboard_shift"
            android:keyWidth="15%p" />
        <Key
            android:codes="122"
            android:keyLabel="z" />
        <Key
            android:codes="120"
            android:keyLabel="x" />
        <Key
            android:codes="99"
            android:keyLabel="c" />
        <Key
            android:codes="118"
            android:keyLabel="v" />
        <Key
            android:codes="98"
            android:keyLabel="b" />
        <Key
            android:codes="110"
            android:keyLabel="n" />
        <Key
            android:codes="109"
            android:keyLabel="m" />
        <Key
            android:codes="-5"
            android:isRepeatable="true"
            android:keyEdgeFlags="right"
            android:keyIcon="@drawable/sym_keyboard_delete"
            android:keyWidth="15%p" />
    </Row>

    <Row android:rowEdgeFlags="bottom">
        <Key
            android:codes="-2"
            android:keyLabel="\?123"
            android:keyWidth="12%p" />
        <Key
            android:codes="44"
            android:keyLabel=","
            android:keyWidth="13%p" />
        <Key
            android:codes="-101"
            android:keyIcon="@drawable/sym_keyboard_language_switch"
            android:keyWidth="10%p" />
        <Key
            android:codes="32"
            android:isRepeatable="true"
            android:keyIcon="@drawable/sym_keyboard_space"
            android:keyWidth="35%p" />
        <Key
            android:codes="46"
            android:keyLabel="."
            android:keyWidth="13%p" />
        <Key
            android:codes="10"
            android:keyEdgeFlags="right"
            android:keyIcon="@drawable/sym_keyboard_return"
            android:keyWidth="17%p" />
    </Row>
</Keyboard>  

   // Other layout can be found in github repo


6. Create a Class (Service) 


/** * Created by ankit on 4/4/16. */
   public class SoftKeyboard extends InputMethodService
        implements KeyboardView.OnKeyboardActionListener {
    static final boolean DEBUG = false;
    LinearLayout view;

    /**
  * This boolean indicates the optional example code for performing   
  * processing of hard keys in addition to regular text generation    
  * from on-screen interaction.  It would be used for input methods that  
  * perform language translations (such as converting text entered on   
  * a QWERTY keyboard to Chinese), but may not be used for input methods  
  * that are primarily intended to be used for on-screen text entry.     */  
  static final boolean PROCESS_HARD_KEYS = true;
    private InputMethodManager mInputMethodManager;
    private LatinKeyboardView mInputView;
    private CandidateView mCandidateView;
    private CompletionInfo[] mCompletions;

    private StringBuilder mComposing = new StringBuilder();
    private boolean mPredictionOn;
    private boolean mCompletionOn;
    private int mLastDisplayWidth;
    private boolean mCapsLock;
    private long mLastShiftTime;
    private long mMetaState;

    private LatinKeyboard mSymbolsKeyboard;
    private LatinKeyboard mSymbolsShiftedKeyboard;
    private LatinKeyboard mQwertyKeyboard;

    private LatinKeyboard mCurKeyboard;

    private String mWordSeparators;


    //Added for image upload 
   private String UPLOAD_URL = "http://simplifiedcoding.16mb.com/VolleyUpload/upload.php";
    private static final String KEY_IMAGE = "key_image";
    private static final String KEY_NAME = "key_name";
    private Bitmap bitmap;

    //
    /**
   * Main initialization of the input method component.  Be sure to call  
   * to super class.     */  
  @Override
    public void onCreate() {
        super.onCreate();
        mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
        mWordSeparators = getResources().getString(R.string.word_separators);
    }

    /**
      * This is the point where you can do all of your UI initialization.  It  
      * is called after creation and any configuration change.    
      */ 

   @Override 
   public void onInitializeInterface() {
        if (mQwertyKeyboard != null) {
          
   // Configuration changes can happen after the keyboard gets recreated,        
    // so we need to be able to re-build the keyboards if the available        
    // space has changed.       
     int displayWidth = getMaxWidth();
            if (displayWidth == mLastDisplayWidth) return;
            mLastDisplayWidth = displayWidth;
        }
        mQwertyKeyboard = new LatinKeyboard(this, R.xml.qwerty);
        mSymbolsKeyboard = new LatinKeyboard(this, R.xml.symbols);
        mSymbolsShiftedKeyboard = new LatinKeyboard(this, R.xml.symbols_shift);
    }

    /**
     * Called by the framework when your view for creating input needs to  
       * be generated.  This will be called the first time your input method    
      * is displayed, and every time it needs to be re-created such as due to   
         * a configuration change.     */   
 @Override 
   public View onCreateInputView() {
        mInputView = (LatinKeyboardView) getLayoutInflater().inflate(R.layout.input, null);
        mInputView.setOnKeyboardActionListener(this);
        setLatinKeyboard(mQwertyKeyboard);
        return mInputView;
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void setLatinKeyboard(LatinKeyboard nextKeyboard) {
        final boolean shouldSupportLanguageSwitchKey =
                mInputMethodManager.shouldOfferSwitchingToNextInputMethod(getToken());
        nextKeyboard.setLanguageSwitchKeyVisibility(shouldSupportLanguageSwitchKey);
        mInputView.setKeyboard(nextKeyboard);
    }


    /**
      * Called by the framework when your view for showing candidates needs to 
    * be generated, like {@link #onCreateInputView}.     */  
 
 @Override 
   public View onCreateCandidatesView() {
        mCandidateView = new CandidateView(this);
        mCandidateView.setService(this);
        return mCandidateView;
    }

    /**
  * This is the main point where we do our initialization of the input method  
  * to begin operating on an application.  At this point we have been     
    * bound to the client, and are now receiving all of the detailed information  
  * about the target of our edits.   
  */    
@Override  
  public void onStartInput(EditorInfo attribute, boolean restarting) {
        super.onStartInput(attribute, restarting);

        // Reset our state.  We want to do this even if restarting, because   
     // the underlying state of the text editor could have changed in any way.     
   mComposing.setLength(0);
        updateCandidates();

        if (!restarting) {
            // Clear shift states.        
    mMetaState = 0;
        }

        mPredictionOn = false;
        mCompletionOn = false;
        mCompletions = null;

        // We are now going to initialize our state based on the type of  
      // text being edited.    
    switch (attribute.inputType & InputType.TYPE_MASK_CLASS) {
            case InputType.TYPE_CLASS_NUMBER:
            case InputType.TYPE_CLASS_DATETIME:
              
           // Numbers and dates default to the symbols keyboard, with    
            // no extra features.              
  mCurKeyboard = mSymbolsKeyboard;
                break;

            case InputType.TYPE_CLASS_PHONE:
                
         // Phones will also default to the symbols keyboard, though 
         // often you will want to have a dedicated phone keyboard.         
       mCurKeyboard = mSymbolsKeyboard;
                break;

            case InputType.TYPE_CLASS_TEXT:
         // This is general text editing.  We will default to the       
         // normal alphabetic keyboard, and assume that we should              
         // be doing predictive text (showing candidates as the
         // user types).        
        mCurKeyboard = mQwertyKeyboard;
                mPredictionOn = true;

          // We now look for a few special variations of text that will      
          // modify our behavior.           
     int variation = attribute.inputType & InputType.TYPE_MASK_VARIATION;
                if (variation == InputType.TYPE_TEXT_VARIATION_PASSWORD ||
                        variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
       // Do not display predictions / what the user is typing             
       // when they are entering a password.           
         mPredictionOn = false;
                }

                if (variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS 
 || variation == InputType.TYPE_TEXT_VARIATION_URI 
 || variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
                  
  // Our predictions are not useful for e-mail addresses  or URIs.            
        mPredictionOn = false;
                }

                if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
                 
       // If this is an auto-complete text view, then our predictions               
        // will not be shown and instead we will allow the editor         
      // to supply their own.  We only show the editor's         
      // candidates when in fullscreen mode, otherwise relying        
      // own it displaying its own UI.             
            mPredictionOn = false;
                    mCompletionOn = isFullscreenMode();
                }

      // We also want to look at the current state of the editor          
      // to decide whether our alphabetic keyboard should start out            
        // shifted.             
   updateShiftKeyState(attribute);
                break;

            default:
         // For all unknown input types, default to the alphabetic       
         // keyboard with no special features.          
      mCurKeyboard = mQwertyKeyboard;
                updateShiftKeyState(attribute);
        }

        // Update the label on the enter key, depending on what the application   
            // says it will do.      
  mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions);
    }

    /** 
     * This is called when the user is done editing a field.  We can use  
      * this to reset our state.     */  
  @Override   
 public void onFinishInput() {
        super.onFinishInput();

        // Clear current composing text and candidates.   
     mComposing.setLength(0);
        updateCandidates();

    // We only hide the candidates window when finishing input on    
    // a particular editor, to avoid popping the underlying application     
   // up and down if the user is entering text into the bottom of     
   // its window.     
   setCandidatesViewShown(false);
        mCurKeyboard = mQwertyKeyboard;
        if (mInputView != null) {
            mInputView.closing();
        }
    }

    @Override    public void onStartInputView(EditorInfo attribute, boolean restarting) {
        super.onStartInputView(attribute, restarting);
        // Apply the selected keyboard to the input view.   
     setLatinKeyboard(mCurKeyboard);
        mInputView.closing();
        final InputMethodSubtype subtype = mInputMethodManager.getCurrentInputMethodSubtype();
        mInputView.setSubtypeOnSpaceKey(subtype);
    }

    @Override    public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) {
        mInputView.setSubtypeOnSpaceKey(subtype);
    }

    /**     * Deal with the editor reporting movement of its cursor.     */   
 @Override    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
                                  int newSelStart, int newSelEnd,
                                  int candidatesStart, int candidatesEnd) {
        super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
                candidatesStart, candidatesEnd);

   // If the current selection in the text view changes, we should     
   // clear whatever candidate text we have.   
     if (mComposing.length() > 0 && (newSelStart != candidatesEnd
                || newSelEnd != candidatesEnd)) {
            mComposing.setLength(0);
            updateCandidates();
            InputConnection ic = getCurrentInputConnection();
            if (ic != null) {
                ic.finishComposingText();
            }
        }
    }

    /** * This tells us about completions that the editor has determined based    
 * on the current text in it.  We want to use this in fullscreen mode   
  * to show the completions ourself, since the editor can not be seen   
  * in that situation.     */  
  @Override
   public void onDisplayCompletions(CompletionInfo[] completions) {
        if (mCompletionOn) {
            mCompletions = completions;
            if (completions == null) {
                setSuggestions(null, false, false);
                return;
            }

            List<String> stringList = new ArrayList<String>();
            for (int i = 0; i < completions.length; i++) {
                CompletionInfo ci = completions[i];
                if (ci != null) stringList.add(ci.getText().toString());
            }
            setSuggestions(stringList, true, true);
        }
    }

    /**
 * This translates incoming hard key events in to edit operations on an   
  * InputConnection.  It is only needed when using the  
   * PROCESS_HARD_KEYS option.     */  
  private boolean translateKeyDown(int keyCode, KeyEvent event) {
        mMetaState = MetaKeyKeyListener.handleKeyDown(mMetaState,
                keyCode, event);
        int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(mMetaState));
        mMetaState = MetaKeyKeyListener.adjustMetaAfterKeypress(mMetaState);
        InputConnection ic = getCurrentInputConnection();
        if (c == 0 || ic == null) {
            return false;
        }

        boolean dead = false;
        if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
            dead = true;
            c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;
        }

        if (mComposing.length() > 0) {
            char accent = mComposing.charAt(mComposing.length() - 1);
            int composed = KeyEvent.getDeadChar(accent, c);
            if (composed != 0) {
                c = composed;
                mComposing.setLength(mComposing.length() - 1);
            }
        }

        onKey(c, null);

        return true;
    }

    /**
* Use this to monitor key events being delivered to the application.   
  * We get first crack at them, and can either resume them or let them   
  * continue to the app.     */  

  @Override    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK:
               
     // The InputMethodService already takes care of the back         
       // key for us, to dismiss the input method if it is shown.           
     // However, our keyboard could be showing a pop-up window        
        // that back should dismiss, so we first allow it to do that.  

              if (event.getRepeatCount() == 0 && mInputView != null) {
                    if (mInputView.handleBack()) {
                        return true;
                    }
                }
                break;

            case KeyEvent.KEYCODE_DEL:
               
       // Special handling of the delete key: if we currently are        
       // composing text for the user, we want to modify that instead      
       // of let the application to the delete itself.        

        if (mComposing.length() > 0) {
                    onKey(Keyboard.KEYCODE_DELETE, null);
                    return true;
                }
                break;

            case KeyEvent.KEYCODE_ENTER:
                // Let the underlying text editor always handle these.        
        return false;

            default:
       // For all other keys, if we want to do transformations on        
        // text being entered with a hard keyboard, we need to process         
       // it and do the appropriate action.      
          if (PROCESS_HARD_KEYS) {
                    if (keyCode == KeyEvent.KEYCODE_SPACE && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0) {
         // A silly example: in our input method, Alt+Space                
        // is a shortcut for 'android' in lower case.

         InputConnection ic = getCurrentInputConnection();
                        if (ic != null) {
           // First, tell the editor that it is no longer in the            
            // shift state, since we are consuming this.       
                ic.clearMetaKeyStates(KeyEvent.META_ALT_ON);
                            keyDownUp(KeyEvent.KEYCODE_A);
                            keyDownUp(KeyEvent.KEYCODE_N);
                            keyDownUp(KeyEvent.KEYCODE_D);
                            keyDownUp(KeyEvent.KEYCODE_R);
                            keyDownUp(KeyEvent.KEYCODE_O);
                            keyDownUp(KeyEvent.KEYCODE_I);
                            keyDownUp(KeyEvent.KEYCODE_D);
                          
            // And we consume this event.            
                return true;
                        }
                    }
                    if (mPredictionOn && translateKeyDown(keyCode, event)) {
                        return true;
                    }
                }
        }

        return super.onKeyDown(keyCode, event);
    }

    /**
* Use this to monitor key events being delivered to the application. 
* We get first crack at them, and can either resume them or let them  
* continue to the app.     */ 
   @Override    public boolean onKeyUp(int keyCode, KeyEvent event) {
    // If we want to do transformations on text being entered with a hard   
     // keyboard, we need to process the up events to update the meta key    
    // state we are tracking.  

      if (PROCESS_HARD_KEYS) {
            if (mPredictionOn) {
                mMetaState = MetaKeyKeyListener.handleKeyUp(mMetaState,
                        keyCode, event);
            }
        }

        return super.onKeyUp(keyCode, event);
    }

    /**
    * Helper function to commit any text being composed in to the editor.  
   */  

  private void commitTyped(InputConnection inputConnection) {
        if (mComposing.length() > 0) {
            inputConnection.commitText(mComposing, mComposing.length());
            mComposing.setLength(0);
            updateCandidates();
        }
    }

    /**
* Helper to update the shift state of our keyboard based on the initial  
   * editor state.     */ 
   private void updateShiftKeyState(EditorInfo attr) {
        if (attr != null && mInputView != null && mQwertyKeyboard == mInputView.getKeyboard()) {
            int caps = 0;
            EditorInfo ei = getCurrentInputEditorInfo();
            if (ei != null && ei.inputType != InputType.TYPE_NULL) {
                caps = getCurrentInputConnection().getCursorCapsMode(attr.inputType);
            }
            mInputView.setShifted(mCapsLock || caps != 0);
        }
    }

    /** * Helper to determine if a given character code is alphabetic.     */   

 private boolean isAlphabet(int code) {
        if (Character.isLetter(code)) {
            return true;
        } else {
            return false;
        }
    }

    /** * Helper to send a key down / key up pair to the current editor.     */  
 
 private void keyDownUp(int keyEventCode) {
        getCurrentInputConnection().sendKeyEvent(
                new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode));
        getCurrentInputConnection().sendKeyEvent(
                new KeyEvent(KeyEvent.ACTION_UP, keyEventCode));
    }

    /*** Helper to send a character to the editor as raw key events.     */  

  private void sendKey(int keyCode) {
        switch (keyCode) {
            case '\n':
                keyDownUp(KeyEvent.KEYCODE_ENTER);
                break;
            default:
                if (keyCode >= '0' && keyCode <= '9') {
                    keyDownUp(keyCode - '0' + KeyEvent.KEYCODE_0);
                } else {
                    getCurrentInputConnection().commitText(String.valueOf((char) keyCode), 1);
                }
                break;
        }
    }

    // Implementation of KeyboardViewListener  
  public void onKey(int primaryCode, int[] keyCodes) {
        if (isWordSeparator(primaryCode)) {
            // Handle separator            if (mComposing.length() > 0) {
                commitTyped(getCurrentInputConnection());
            }
            sendKey(primaryCode);
            updateShiftKeyState(getCurrentInputEditorInfo());
        } else if (primaryCode == Keyboard.KEYCODE_DELETE) {
            handleBackspace();
        } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
            handleShift();
        } else if (primaryCode == Keyboard.KEYCODE_CANCEL) {
            handleClose();
            return;
        } else if (primaryCode == LatinKeyboardView.KEYCODE_LANGUAGE_SWITCH) {
            handleLanguageSwitch();
            return;
        } else if (primaryCode == LatinKeyboardView.KEYCODE_OPTIONS) {
            // Show a menu or somethin'        
} else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE && mInputView != null) {
            Keyboard current = mInputView.getKeyboard();
            if (current == mSymbolsKeyboard || current == mSymbolsShiftedKeyboard) {
                setLatinKeyboard(mQwertyKeyboard);
            } else {
                setLatinKeyboard(mSymbolsKeyboard);
                mSymbolsKeyboard.setShifted(false);
            }
        } else {
            handleCharacter(primaryCode, keyCodes);
        }
    }

    public void onText(CharSequence text) {
        InputConnection ic = getCurrentInputConnection();
        if (ic == null) return;
        ic.beginBatchEdit();
        if (mComposing.length() > 0) {
            commitTyped(ic);
        }
        ic.commitText(text, 0);
        ic.endBatchEdit();
        updateShiftKeyState(getCurrentInputEditorInfo());
    }

    /**
    * Update the list of available candidates from the current composing  
     * text.  This will need to be filled in by however you are determining   
      * candidates.     */   

 private void updateCandidates() {
        if (!mCompletionOn) {
            if (mComposing.length() > 0) {
                ArrayList<String> list = new ArrayList<String>();
                list.add(mComposing.toString());
                setSuggestions(list, true, true);
            } else {
                setSuggestions(null, false, false);
            }
        }
    }

    public void setSuggestions(List<String> suggestions, boolean completions,
                               boolean typedWordValid) {
        if (suggestions != null && suggestions.size() > 0) {
            setCandidatesViewShown(true);
        } else if (isExtractViewShown()) {
            setCandidatesViewShown(true);
        }
        if (mCandidateView != null) {
            mCandidateView.setSuggestions(suggestions, completions, typedWordValid);
        }
    }

    private void handleBackspace() {
        final int length = mComposing.length();
        if (length > 1) {
            mComposing.delete(length - 1, length);
            getCurrentInputConnection().setComposingText(mComposing, 1);
            updateCandidates();
        } else if (length > 0) {
            mComposing.setLength(0);
            getCurrentInputConnection().commitText("", 0);
            updateCandidates();
        } else {
            keyDownUp(KeyEvent.KEYCODE_DEL);
        }
        updateShiftKeyState(getCurrentInputEditorInfo());
    }

    private void handleShift() {
        if (mInputView == null) {
            return;
        }

        Keyboard currentKeyboard = mInputView.getKeyboard();
        if (mQwertyKeyboard == currentKeyboard) {
            // Alphabet keyboard            checkToggleCapsLock();
            mInputView.setShifted(mCapsLock || !mInputView.isShifted());
        } else if (currentKeyboard == mSymbolsKeyboard) {
            mSymbolsKeyboard.setShifted(true);
            setLatinKeyboard(mSymbolsShiftedKeyboard);
            mSymbolsShiftedKeyboard.setShifted(true);
        } else if (currentKeyboard == mSymbolsShiftedKeyboard) {
            mSymbolsShiftedKeyboard.setShifted(false);
            setLatinKeyboard(mSymbolsKeyboard);
            mSymbolsKeyboard.setShifted(false);
        }
    }

    private void handleCharacter(int primaryCode, int[] keyCodes) {
        if (isInputViewShown()) {
            if (mInputView.isShifted()) {
                primaryCode = Character.toUpperCase(primaryCode);
            }
        }
        if (isAlphabet(primaryCode) && mPredictionOn) {
            mComposing.append((char) primaryCode);
            getCurrentInputConnection().setComposingText(mComposing, 1);
            updateShiftKeyState(getCurrentInputEditorInfo());
            updateCandidates();
        } else {
            getCurrentInputConnection().commitText(
                    String.valueOf((char) primaryCode), 1);
        }
    }

    private void handleClose() {
        commitTyped(getCurrentInputConnection());
        requestHideSelf(0);
        mInputView.closing();
    }

    private IBinder getToken() {
        final Dialog dialog = getWindow();
        if (dialog == null) {
            return null;
        }
        final Window window = dialog.getWindow();
        if (window == null) {
            return null;
        }
        return window.getAttributes().token;
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void handleLanguageSwitch() {
        mInputMethodManager.switchToNextInputMethod(getToken(), false /* onlyCurrentIme */);
    }

    private void checkToggleCapsLock() {
        long now = System.currentTimeMillis();
        if (mLastShiftTime + 800 > now) {
            mCapsLock = !mCapsLock;
            mLastShiftTime = 0;
        } else {
            mLastShiftTime = now;
        }
    }

    private String getWordSeparators() {
        return mWordSeparators;
    }

    public boolean isWordSeparator(int code) {
        String separators = getWordSeparators();
        return separators.contains(String.valueOf((char) code));
    }

    public void pickDefaultCandidate() {
        pickSuggestionManually(0);
    }

    public void pickSuggestionManually(int index) {
        if (mCompletionOn && mCompletions != null
 && index >= 0 && index < mCompletions.length) {
            CompletionInfo ci = mCompletions[index];
            getCurrentInputConnection().commitCompletion(ci);
            if (mCandidateView != null) {
                mCandidateView.clear();
            }
            updateShiftKeyState(getCurrentInputEditorInfo());
        } else if (mComposing.length() > 0) {
            // If we were generating candidate suggestions for the current  
          // text, we would commit one of them here.  But for this sample,      
      // we will just commit the current text.       

     commitTyped(getCurrentInputConnection());
        }
    }

    public void swipeRight() {
        if (mCompletionOn) {
            pickDefaultCandidate();
        }
    }

    public void swipeLeft() {
        handleBackspace();
    }

    public void swipeDown() {
        handleClose();
    }

    public void swipeUp() {
    }

    public void onPress(int primaryCode) {
    }

    public void onRelease(int primaryCode) {
    }

    @Override    public void onDestroy() {
        super.onDestroy();
    }

    private void takeScreenshot() {
        Date now = new Date();
        android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now);

        try {
            // image naming and path  to include sd card  appending name you choose for file    

        String mPath = Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpg";

            view = new LinearLayout(getApplicationContext());
            WindowManager wm = (WindowManager) getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE);
            Display display = wm.getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);
            int width = size.x;
            int height = size.y;
            view.setLayoutParams(new ViewGroup.LayoutParams(width, height));
            // create bitmap screen capture            View v1 = view.getRootView();
            v1.setDrawingCacheEnabled(true);
            Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
            v1.setDrawingCacheEnabled(false);

            File imageFile = new File(mPath);

            FileOutputStream outputStream = new FileOutputStream(imageFile);
            int quality = 100;
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
            outputStream.flush();
            outputStream.close();
            Log.d("Screen", "taken");
            //openScreenshot(imageFile);        } catch (Throwable e) {
            // Several error may come out with file handling or OOM      

      e.printStackTrace();
        }
    }
}
And you are done keyboard now...
If you like it, then like it on Facebook and recommend on G+
Full Source code can be downloaded from here