Showing posts with label Mobile Application. Show all posts
Showing posts with label Mobile Application. Show all posts

Saturday, May 20, 2017

React Native undefined is not an object (evaluating 'this.props.navigator.push)

Hello,

Recently we have been working with React Native for one of our application where we faced an issue with Android Navigator. Basically we had two lists Category List and Sub Category List and on tap of category list item we wanted to render sub category list. Following is the code for that.

<TouchableOpacity onPress={()=> this.pressRow(rowData)} >
<CardSection>
 <View style={thumbnailContainerStyle}>
<Image
 style={thumbnailStyle}
 source={{ uri: rowData.image }}
/>
 </View>
 <View style={headerContentStyle}>
<Text style={headerTextStyle}>{rowData.name}</Text>
 </View>
</CardSection>
</TouchableOpacity>

And following is function where we were using navigator.push to go to next view.

pressRow (rowData) {

    if(rowData.subcategory == true)
    {
      this.props.navigator.push({
        name: SubCategoryList,
        passProps: {rowId:rowData.id}
      });
    }
    else if(rowData.subcategory == false)
    {
      this.props.navigator.push({
        name: ProductList,
        passProps: {rowId:rowData.id}
      });
    }

 }

Here we are getting problem with error, this.props.navigator is undefined so were not able to go to second screen.

The problem here is on scope as we were having category list rendered in app container like this.


<CategoryList />

So props of parent are not passed to child and hence navigator was not available. To solve this all you have to do it add your child component like this.

<CategoryList  navigator={this.props.navigator} />

And now navigator object will be available. Hope this solves your problem.


Saturday, April 29, 2017

Step By Step Guide to Install React Native and Create Mobile App in OSX

Hello,

Recently in projects we decided to use React Native to create cross platform mobile application. I faced some difficulties in installing ReactNative so here in this blog I will explain getting started with React Native and create cross platform mobile application.

1) Install Xcode and Xcode command lines tools.



Get Xcode from Mac App Store. Click Here

2) Install Xcode Command Line Tools, Open terminal and run following command.

xcode-select --install

3) Install Homebrew, Homebrew is a package manager to install missing package on OSX. Open terminal and run following command.

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

4) Install NodeJs and NPM. React comes package in NPM so we have to install it. Run following command in terminal

brew install node

After installation check with following command to see if it's installed.

node -v

npm -v

5) Install watchman with home brew.

brew install watchman

6) Install The React Native CLI

Node.js comes with npm, which lets you install the React Native command line interface.

Run the following command in a Terminal

npm install -g react-native-cli

7) Create React Native Project, run following commands in terminal.

react-native init ReactNativeTest

cd ReactNativeTest

Now run it with following command.

react-native run-ios

It will run application in iOS simulator.


react-native run-ios is just one way to run your app. You can also run it directly from within Xcode.



Step By Step Guide to Install and Create ReactJs Application in OSX

Hello,

Recently we have decided to use ReactJs for building mobile web applications and I faced some difficulties in setting up ReactJs in OSX so here in this blog I will explain step by step procedure from installation of ReactJS to creating and running application and Getting started with ReacJs in OSX

1) Install Xcode and Xcode command lines tools.



Get Xcode from Mac App Store. Click Here

2) Install Xcode Command Line Tools, Open terminal and run following command.

xcode-select --install

3) Install Homebrew, Homebrew is a package manager to install missing package on OSX. Open terminal and run following command.

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

4) Install NodeJs and NPM. React comes package in NPM so we have to install it. Run following command in terminal

brew install node

After installation check with following command to see if it's installed.

node -v

npm -v

5) Next we will install React, run following command in terminal.

npm install react

6) Now we will install Command line utility to create react app. Run following command in terminal.

npm install -g create-react-app

7) Create new react app. Run following commands in terminal.

create-react-app ReactApp
cd ReactApp
npm start

It should display following message in terminal.



And it will open ReactApp in your default browser.




That's it, Now you can work on ReactApp code and just refresh it in browser to see effect. Hope this helps you.






Monday, February 20, 2017

Stop User From Uninstalling Your Mobile App

I have been developing mobile applications since last 5 years and over this period of time I have developed many applications for Android and iOS. These applications includes both native and hybrid applications. In this blog I am going to explain certain important things you should consider while developing mobile app so users won't uninstall after using it. These is based on my own experience of developing mobile applications. You may have other views on this. Let me know your views in comments.

Do not increase size of your mobile application


This is first and foremost factor you have to consider while developing mobile application. Now a days storage is biggest concern in smart phones. You have so much other data like photos, videos, musics etc. So at most of the time you get waring of "Storage space running low" at this time users will uninstall mobiles apps which is taking too much space. So if your mobile application is heavy in size and consume lots of spaces on your mobile phone at one point of time, users will going to uninstall your application so make sure you keep size of your application to some limits. Make sure you store data in SD cards so that your application does not consume much size. Try to clean up storage space from the app so that you do not have unnecessary data.

Real Life Story : Let me give you an example on how we reduced size of mobile app. In one of the app we need to have text to speech function. There is a lesson and user can play audio of that lesson and can hear it. So we decided to use in built text to speech function of android so we don't have to include MP4 files of audios.

Make it efficient to consume less data and battery


People now a days are very conscious about their phones, they can not live without it so they make sure that there is always active data connection and mobile battery is always charged. In this case if your application is consuming too much data and battery and your user has to charge it very often then there is high chance that they will uninstall your application. So make sure if you have functions like background services, GPS , location tracking, you also have strategy to save battery power. Always use power saving strategy. At the same time make sure your application is not using too much network data.

Real life story : We created mobile app to background location tracking. First we were tracking user location each 10 seconds for very accurate tracking but battery of mobile phone was always drained so later we changed location strategy and tracked user location based on considerable movements and at regular time interval of 5 minutes and used network locations as well.


Make sure they understand application


This problem is particularly with business applications where users of mobile app have difficulties in understanding functions of the app. They do not understand the flow and screens of the app and hence they get confused and stop using application. This rate is very high in business app and business app comes with strict requirements and flow as per each business and users have to understand it. To solve this problem you can include tutorials in your mobile application. You can use overlay tutorials on your mobile application screens to point out functions of each buttons and screens so user will know where to tap and what's the flow of the app.


Make sure application is bug free and do not crash often


If your application crashes often and have bugs your user is going to be annoyed with your app and will uninstall your application so make sure your application is bug free and do not crash. Although most of the developers will make their application bug free but still sometimes it happens that your mobile app crashes due to some reasons and no user will like it. So make sure you handle all the errors and exception properly.


Allow user to remove Ads


Well, the ultimate aim of the mobile application is to generate revenue from it and for that most of the users will put ads in the mobile app but sometimes these ads are annoying for end users. Specifically the ads which pop ups suddenly and stops users from doing work with app. Specifically for the games user will not like ads if it is not letting them play games properly so user will uninstall mobile app if you not allow them to remove ads. So yes you can add the ads in mobile app but let user remove it for the session while they are using the application. So they can hide it temporarily and use your app. 

Along with these there are some small tips you can also consider. 

  • Do not annoy user with too much notifications
  • Make UI very fast and responsive
  • Choose color scheme properly
  • Make it responsive to fit in all the screens
  • Do not use big images


If you consider these factors while developing your app user will not uninstall your app. 

Friday, December 9, 2016

Digital Brochures For Builders, Real Estate Developers

World is going towards digitization but Real Estate Sector is still not using digital technology at it's best. They are still following the old approach of printed brochures to show their development informations and all. This is not just costing them much but this is no more a convenient way.

When I have a smart phone in my hand why should I carry printed, bulky brochure, that can be mis placed or won't be able to give me all the information I need. Instead of that if we have digital brochure, you can just have it in your smart phone. You can check it anytime, it does not consume much space and will be available anytime.


For the digital brochures, a mobile application is the best way to deliver. If you are in real estate business, then having mobile app for your projects will be one of the best way to market your projects and get more customers. A mobile application with all the features to showcase your project can boost your sales and customer engagements.

Mobile application can easily be downloaded and installed in phone. Your customer can find it and can see your projects. You can send notifications to customers for your upcoming projects. You can show entire gallery of your projects. You can show your project location on map, so customer can see exact location and app can guide them to reach at your project easily instead of manually finding a way.

I will give you more information by giving an example of the app we created for leading real estate developer of Gujarat.

Recently we created Digital Brochure Mobile Application for KP Sanghvi Infra for show casing their projects. I will give more informations about the features we added in the app. You can check application on Google Play Store


1) Show your projects according to category like Residential and Commercial



2) Show list of the projects according to selected category.



3) Let the user filter it based on project status and city



4) Show All the Information about selected project.


5) Show Project Gallery with filter like Floor Plan, 3D Photos etc, Since it's digital photographs, there is no limit.



6) Show Exact Project Location on Map and Guide user to come to your location easily.




So with this approach, your customer will have all your information in their. They can check and share it with others anytime. You can send notifications to customers. 

So go digital with this solution, if you need one contact us at.

Email : info@thedesignshop.co.in

Thursday, December 8, 2016

5 Simple Questions To Decide Hybrid vs Native Mobile App Development



If you’re confused and wondering whether to build a hybrid mobile app or a native mobile app, this article will help you decide the mobile app strategy.

Quick introduction to Hybrid and Native app

Hybrid App: Developer wraps web code (HTML / CSS / JavaScript) with native SDK. Can be easily deployed across multiple platform and is usually the cheaper and faster solution.

Native App: This is platform (iOS, Android etc.) specific and requires unique expertise. However the full potential of the platform can be leveraged which will drive great user experience and larger app capabilities (especially around phone hardware).

Following 5 simple questions will help you decide between Hybrid vs Native App Development.

1) Do you want to use Hardware and Native Features.

In your application if you want to use phone hardware like GPS, Camera, SD card etc, it's recommended to go for native app instead of hybrid app. Because native SDK has support to access hardware, For hybrid app depending on the framework, you may or may not hardware access. Also you have to consider performance as well. For example in one my project there was a requirement to get camera preview in the app and capture it. Initially I build hybrid app but camera preview was sluggish and slow so later I have to move to native app. If there is no requirement to access hardware then hybrid application is the best option.

2) Is the UI experience is more important in your application?

If you want to create an insane user experience, the native app approach would do better. A hybrid app can never match the level of user experience that you get in a native app. However, this doesn’t mean that the user experience of a hybrid app is bad. A good front-end developer in hybrid app can get close to a native experience. Also performance of native app is much better than hybrid app so when there is a high demand of performance, go for native app.

3) Does your app need background services?

If your application need to work in background like background location tracking, file download in background then native app is the best option as native SDK has classes to create background services that can be invoked by alarms etc. In hybrid app, if app is background or killed, all the process stops.

4) What is your Development Time and Budget?

If you have very limited budget and want to get app quickly to the market then hybrid app is the best option as you don't have to create separate application for each platform. One single code wrapped with multiple native wrappers will give you native application for different platform so it will save both time and cost. As for the single native app you have to hire native developers, while for hybrid app one developer is enough and it can be quickly developed and deployed to multiple platform.

5) Does your application need offline storage?

Most of the apps are built work offline and for this we need local database storage in app. If your application need more space for offline storage than native app is best option. However it's possible to have offline storage in hybrid app too. But there is a limitation up to certain MB. After that it does not allow more offline storage.


With these 5 questions you can define your development strategy.

Saturday, October 22, 2016

Send FireBase Push notifications from PHP Application

Hello,

Recently in one of my project we have mobile applications with PHP web services. In this we have a requirement to send Firebase Push notifications from PHP to mobile app. Here in this blog I am going to explain how to do this.

First all login to your Firebase console and get the Web Api key. Go to https://console.firebase.google.com/ and login with your user name and password.

Select your project



Click on gear icons on left and select project settings and above screen will be displayed. Here Web Api Key is the key which you need. copy it. Now let see code one by one.

$url = 'https://fcm.googleapis.com/fcm/send';

This is the URL we will use to send push notification.

Now lets build the payload.

$fields = array (
'to' => 'REGISTRATION_KEY',
"notification" => array(
"title"=> "Welcome To App",
"body"=> "App Description"
),
"data"=>array(
"key_1"=>"value_1",
                        "key_2"=>"value_2"
)
);

Here to is the filed which contains registration id for the device. This is the id which you get when you register device for push notification.

notification contains title and text to be displayed in notification area. This is a standard format and should not be changed.

data contains all the user defined data you want to send with notification, you can add any number of key value pairs here.

If you don't want to pass any data, remove the data field from payload. So now payload is read now lets encode it to send.

$fields = json_encode ( $fields );

Now send headers with API key.

$headers = array (
'Authorization: key=' . "YOUR_WEB_API_KEY",
'Content-Type: application/json'
);

Now we will use PHP cURL to send HTTP request.

$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $url );
curl_setopt ( $ch, CURLOPT_POST, true );
curl_setopt ( $ch, CURLOPT_HTTPHEADER, $headers );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $fields );

$result = curl_exec ( $ch );
echo $result;
curl_close ( $ch );

That's it and Push notification is sent to particular device.

Add Google Place Auto Suggest to Sencha Touch

Hello,

Recently in one of my project we had a requirement to add Google Place Auto Suggest in Sencha Touch app and I faced certain issue in that so in this blog I am going to explain how to do this.

You can get more information about google place auto suggest from following link.

https://developers.google.com/places/web-service/autocomplete

When you implement it in any web app you will get following result.


As when you start typing it will give you suggestions and you can pick any one suggestion from it.

When we implement same thing with Sencha Touch text field it was working fine. When you start typing suggestions were working but the problem was when user tap to pick one of the suggestion it was not working. It just closes the suggestions and nothing is saved in textfield. There were some solutions like adding some classes and all. I tried everything but it was not working at all. So I came up with different solution. First of all add following textfield in your view.

{
xtype: 'panel',
flex:'1',
items:[
{
xtype: 'textfield',
placeHolder: 'TYPE IN THE CITY OR THE ADDRESS',
itemId: 'autoSuggest',
id: 'autoSuggest',
height: 10,
inputCls:'x-input-el x-form-field x-input-text grey-input',
name: 'address',
allowBlank: false,
autoCapitalize: false,
clearIcon: false
}
]
}


Now bind key up event for this textfield in your controller.

'#autoSuggest': {
keyup: 'onSearchAddressTap'
}

Now our logic is the query Google place API manually and store result in Data Store and show it in dataview. So we will need model and store.

Following is our model.

Ext.define('MYAPP.model.AddressSuggestion', {
    extend: 'Ext.data.Model',
    config: {
        fields: [
            { name: "description", type: 'string' }

        ]
    }
});

And Following is our store.


Ext.define('MYAPP.store.AddressSuggestion',{
    extend:'Ext.data.Store',
    config:{
        model: 'MYAPP.model.AddressSuggestion',
        autoLoad: true,
        proxy:{
            type: 'memory'
        }
    }
});

Now lets key up event.

onSearchAddressTap: function(textField){
Ext.getStore('AddressSuggestion').removeAll();
if(textField.getValue().length > 3){
this.getVenueAddress().show();
Ext.Ajax.request({
url : 'https://maps.googleapis.com/maps/api/place/autocomplete/json?input='+textField.getValue()+'&types=geocode&language=fr&key=YOURKEY',

scope : this,
//method to call when the request is successful
success:function(response,opts)
{
var result = Ext.decode(response.responseText);
for(var i =0;i
Ext.getStore('AddressSuggestion').add({'description':result.predictions[i].description});
}
console.log(result);
},

failure:function(err)
{

}
});
}
}

So as you can see above we are sending an Ajax request to google maps api and store result in Datastore. 

Now add following dataview in your view just below the above textfield.

{
xtype: 'panel',
flex: '1',
layout: 'fit',
items: [
{
xtype   : 'dataview',
margin: '0 20 0 20',
itemId: 'venueAddress',
id: 'venueAddress',
itemTpl:
[
'<table style="border-bottom: 1px solid #e3e3e3;"><tr><td style="padding-bottom: 12px;padding-top: 12px;width:95%"><div style="color:#262626;font-size: 15px">{description}</div></td><td><img width="40" height="40" src="resources/images/howMuchSpace.png" /></td></td></tr></table>'
],
store: 'AddressSuggestion'
}

]
}

So now as soon as you start typing you will get result filled up in dataview and then add itemtap event of dataview and get the selected address and hide the dataview.

onVenueAddressItemTap: function(list, index, target, record, e){
this.getAutoSuggest().setValue(record.get('description'));
this.getVenueAddress().hide();
}

Ultimate output is like following.



Hope this helps you.

Saturday, October 15, 2016

Sencha Touch Hide Pickers on Android Back Key Press

Hello,

I recently published an article about hiding sencha touch Message box on press of back button in android. You can read it here Sencha Touch Hide Alert Box on Android Back Button Press

This post is something similar to it. Recently we created an android application with Sencha Touch and Cordova for client. After testing, client came up with requirement that if any picker is open for example calendar picker or select field picker etc. It should be closed on press of back button in android. So after efforts of half an hour, I found a solution. 

In Sencha Touch pickers are basically floating panels. So what we have to do it get all the floating panels and see if it's hidden or not. If not hidden then hide it.

First of all you have to bind back button event of android using cordova. Please check this cordova document on how to do this here.

Once you add backbutton listener, add following code.

var floatingComponents = Ext.query('.x-floating');
for(var i=0;i
var component = Ext.getCmp(floatingComponents[i].id);
if(component){
if(component.isHidden() == false){
component.hide();
return;
}
}
}

As you can see in above code, first we are finding all the floating component using Ext.query and class x-flaoting

Then we loop through it and find component using id of floating component and check if component is not hidden then hide it and return from there. 

Hope this helps you.

Saturday, October 1, 2016

Android Adding Button Click Action In Notification Bar

Hello,

Recently in one of my project we have a requirement to add button in notification area and do some actions when button is clicked. So here in this blog I am going to explain how to do this.

First of all Add following XML file in your layout and name it as custom_notification. This will have definition for button we are going to add in notification bar.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    android:gravity="center_vertical"
    android:orientation="vertical" >

<Button 
        android:id="@+id/myButton" 
        android:layout_width="wrap_content" 
        android:layout_height="40sp" 
        android:layout_weight="1" 
        android:text="Click Me"
        android:textColor="#000000"
        android:textSize="10sp">
    </Button>


</LinearLayout>

Now in your MainActivity add following function and call it in onCreate method to create notification with button.

public void createNotificationInNotificationBar(){
int icon = R.drawable.ic_launcher;
long when = System.currentTimeMillis();
Notification notification = new Notification(icon, "Click Me To Do Some Action", when);

NotificationManager mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
contentView = new RemoteViews(getPackageName(), R.layout.custom_notification);
notification.contentView = contentView;
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.contentIntent = contentIntent;
notification.flags |= Notification.FLAG_NO_CLEAR; //Do not clear the notification
}

Above code will create notification with button. User will not be able to clear this notification. Now we will add click action handler to button. Add following lines at end of above function.

Intent myIntent = new Intent("button_clicked");
PendingIntent pendingSwitchIntent = PendingIntent.getBroadcast(this, 0, myIntent, 0);
contentView.setOnClickPendingIntent(R.id. myButton, 
                pendingSwitchIntent);

Now add following code to your Manifest.xml file.


This will create receiver and action. Now add receiver to your main activity.

public static class RecordShareReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent myIntent = new Intent(context.getApplicationContext(), ButtonClickActivity.class);
myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(myIntent);
}
}


This will start ButtonClickActivity. 

public class ButtonClickActivity extends Activity{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//Do your actions here
finish();
}
}

As you can see in above in onCreate method you can do the actions as per your requirement. Once the action is done we finish activity.

Add following code to your android manifest for activity.


android:label="@string/app_name" 
android:launchMode="singleTask" 
android:name=". ButtonClickActivity" 
android:screenOrientation="portrait" 
android:theme="@android:style/Theme.Translucent.NoTitleBar" />


As you can see above we set theme as Translucent theme so activity will not be visible. It will just start do the action and gets finished. 




Saturday, September 3, 2016

PDF.JS Not Working - Sencha Touch 2 PDF Panel Not Working After Build

Hello,

Recently in one of my project we were using following Sencha Touch 2 PDF panel to display PDF in native application build with Cordova.

I faced a strange issue here. App was working fine without any build but when I generate a production build and build the native android app PDF panel stopped working and throws following error.

Unhandled rejection: TypeError: undefined is not an object (evaluating 'viewBox')

I tried to find out a solution for sometime but could not get any. I was using following PDF panel.

https://github.com/SunboX/st2_pdf_panel

Suddenly I saw that there is no update since last three years and that could be probably be the reason. So what I did is downloaded latest PDF.js and built the minified files and used it and bingo it worked. So here I am going to explain the steps.

1) First of clone latest PDF.js source from it's git.

$ git clone git://github.com/mozilla/pdf.js.git

2) Now go to the folder.

$ cd pdf.js

3) Install Node.js if its not installed.

$ npm install -g gulp-cli

4) After node.js is installed, install all the dependencies.

$ npm install

5) Build PDF.js files.

$ gulp generic

it will generate minified files in directory build/generic/build/

Copy pdf.js and pdf.worker.js files from this directory to your lib folder and that's it now PDF will be displayed even in testing or production build.

Saturday, August 13, 2016

Android Record Video in Background Without Preview

Hello,

Recently in one of my project we have a requirement to record video in background with just one button click. No need to display preview or no need of user action, like tap record button. And also stop video recording with just one button click.

In this blog I am going to explain how to do this.

So I have used Android Media Recorder for the same. Since it was not working without preview I added SurfaceView with hidden mode by setting height to 1 so nobody can see it.

First of all lets add some global variables.

View webview;
private Camera mCamera;
private SurfaceView mPreview;
private MediaRecorder mMediaRecorder;
File outputFile;
public static final int MEDIA_TYPE_IMAGE = 1;

public static final int MEDIA_TYPE_VIDEO = 2;

Since we are adding surface view dynamically, add following class to your activity.

    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
        private SurfaceHolder mHolder;
        private Camera mCamera;

        public CameraPreview(Context context, Camera camera) {
            super(context);
            mCamera = camera;

            // Install a SurfaceHolder.Callback so we get notified when the
            // underlying surface is created and destroyed.
            mHolder = getHolder();
            mHolder.addCallback(this);
            // deprecated setting, but required on Android versions prior to 3.0
            mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }

        public void surfaceCreated(SurfaceHolder holder) {
            // The Surface has been created, now tell the camera where to draw the preview.
            try {
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
            } catch (IOException e) {
                Log.d(TAG, "Error setting camera preview: " + e.getMessage());
            }
        }

        public void surfaceDestroyed(SurfaceHolder holder) {
            // empty. Take care of releasing the Camera preview in your activity.
        }

        public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
            // If your preview can change or rotate, take care of those events here.
            // Make sure to stop the preview before resizing or reformatting it.

            if (mHolder.getSurface() == null){
              // preview surface does not exist
              return;
            }

            // stop preview before making changes
            try {
                mCamera.stopPreview();
            } catch (Exception e){
              // ignore: tried to stop a non-existent preview
            }

            // set preview size and make any resize, rotate or
            // reformatting changes here

            // start preview with new settings
            try {
                mCamera.setPreviewDisplay(mHolder);
                mCamera.startPreview();

            } catch (Exception e){
                Log.d(TAG, "Error starting camera preview: " + e.getMessage());
            }
        }
    }  

Now first of all lets prepare everything for for recording.

Button startRecording = (Button) findViewById(R.id.startRecording);
startRecording.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
               initVideoReocrding();
}
});


 public void initVideoReocrding(){
    // Create an instance of Camera
        appView = (Button) findViewById(R.id.mainView)
        mCamera = getCameraInstance();

        // Create our Preview view and set it as the content of our activity.
        mPreview = new CameraPreview(this, mCamera);
        mPreview.setId(107);
        
        android.widget.FrameLayout.LayoutParams params = new android.widget.FrameLayout.LayoutParams(1, 1);
        mPreview.setLayoutParams(params);
        ((ViewGroup) appView.getView().getParent().getParent()).addView(mPreview); 
    }

Since we are adding surface view dynamically we have to call start recording function after sometime.

final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
  @Override
  public void run() {
    startVideoRecording();
  }
}, 1000);

public void startVideoRecording(){
if(prepareVideoRecorder()){
Log.v("MediaRecorder","MediaRecorder is ready");
mMediaRecorder.start();
}
}

Here are the additional function we need for this.

public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}

private void releaseMediaRecorder(){
if (mMediaRecorder != null) {
mMediaRecorder.reset();   // clear recorder configuration
mMediaRecorder.release(); // release the recorder object
mMediaRecorder = null;
mCamera.lock();           // lock camera for later use
}
}

private void releaseCamera(){
if (mCamera != null){
mCamera.release();        // release the camera for other applications
mCamera = null;
}
}

/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type){
 return Uri.fromFile(getOutputMediaFile(type));
}

/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.

File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
 Environment.DIRECTORY_PICTURES), "MYAPP");
// This location works best if you want the created images to be shared
// between applications and persist after your app has been uninstalled.

// Create the storage directory if it does not exist
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("MYAPP", "failed to create directory");
return null;
}
}

// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE){
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
} else if(type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"VID_"+ timeStamp + ".mp4");
} else {
return null;
}

return mediaFile;
}

private boolean prepareVideoRecorder(){

Camera temp = getCameraInstance();
if(temp != null){
mCamera = temp;
}
mMediaRecorder = new MediaRecorder();

// Step 1: Unlock and set camera to MediaRecorder
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);

// Step 2: Set sources
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

// Step 4: Set output file
outputFile = getOutputMediaFile(MEDIA_TYPE_VIDEO);
mMediaRecorder.setOutputFile(outputFile.toString());

// Step 5: Set the preview output
mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());
// Step 6: Prepare configured MediaRecorder
try {
mMediaRecorder.prepare();
} catch (IllegalStateException e) {
Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
} catch (IOException e) {
Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
}
return true;
}


And following is the function to stop recording.

public void stopVideoRecording(){
    mMediaRecorder.stop();  // stop the recording
        releaseMediaRecorder(); // release the MediaRecorder object
        mCamera.lock();  
        mCamera.stopPreview();
        Log.v("OutputFile", outputFile.getAbsolutePath());
        
        MediaScannerConnection.scanFile(getApplicationContext(), new String[]{outputFile.getAbsolutePath()}, null, null);
        View previewView = ((ViewGroup) appView.getView().getParent().getParent()).findViewById(107);
        ((ViewGroup) appView.getView().getParent().getParent()).removeView(previewView);
    }
    




Cordova Camera Plugin Select Video Returns null FILE URI

Hello,

Recently in one of my project we have a requirement to select video from Gallery and import it to Cordova application.

For that I used following code.

        navigator.camera.getPicture(this.onVideoSuccess, function(){
            console.log('Error in Video Processing);
        }, {
            destinationType: Camera.DestinationType.FILE_URI,
            sourceType: navigator.camera.PictureSourceType.PHOTOLIBRARY,
            mediaType:Camera.MediaType.VIDEO,
            limit: 1
        });

As you can see in above code we are selecting media type to video. Following is our callback function.

    onVideoSuccess: function(videoURI){
        console.log(videoURI);
    }

Now the problem was it was always returns null URI for any video I select. So I decided to dig into plugin code and found issue in CameraLauncher.java. Following is the function.


private void processResultFromGallery(int destType, Intent intent) {
 Uri uri = intent.getData();
        if (uri == null) {
            if (croppedUri != null) {
                uri = croppedUri;
            } else {
                this.failPicture("null data from photo library");
                return;
            }
        }
        .........
        .........
Here we have issue in following line.

        String fileLocation = FileHelper.getRealPath(uri, this.cordova);

This always returns null, however we were getting URI. So I added following code. 

if (this.mediaType != PICTURE) {
         if (fileLocation == null) {
         Cursor cursor = null;
          try { 
            String[] proj = { MediaStore.Images.Media.DATA };
            cursor = this.webView.getContext().getContentResolver().query(uri,  proj, null, null, null);
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            fileLocation = cursor.getString(column_index);
          } finally {
            if (cursor != null) {
              cursor.close();
            }
          }
         }
            this.callbackContext.success(fileLocation);
        }

and it worked.  Now it returned correct URI.

Hope this helps you.

Monday, June 20, 2016

Sencha Touch Data Store Tips and Tricks

Recently one my friend asked me for some help on Sencha Touch Data store and form our conversation I got an idea for this blog.

Tip 1

If you want to pass extra params to store there are two ways to do that.

1) Pass it in load method.

store.load({
            params: {
                param1 : value1
            }
        });

2) Set it as extra param.

store.getProxy().setExtraParams({
            'param1' : value1,
            'param2': value2
        });

So what's the difference between this two and when to use which.

When you have requirement to add and use params only once. Also every time store load, you want to pass different params you have to use below method.

store.load({
            params: {
                param1 : value1
            }
        });

Params added here are only added once. Next time when you call load method of store, these params are not passed. You can use it for dynamic parameters.

When you have fixed params that you have to pass every time,  a store is loaded. You have to use following method.

store.getProxy().setExtraParams({
            'param1' : value1,
            'param2': value2
        });


This will permanently add those params to the store and it will be passed every time store.load() method is called.


Tip 2

How can you add callback function for store load dynamically. Again there are two ways to do that. If you want to add and use it only once, use following method. 

store.load({
       callback: function(){
              console.log('store is loaded'); 
       }
});

But if you want to wait for store load every time you should use following logic.

store.on({
       load: function(){
              console.log('store is loaded'); 
       },
       scope: this
});

Tricks

1) To reset all the extra params in store use do the following.

store.getProxy().setExtraParams({
});

Just pass the empty object in function and it will clear all previous params.

2) Reset page param in store when using list paging.

You can use currentPage config. store.currentPage = 1

3) Get raw response from of store load.

store.getProxy().getReader().rawData

This will return you all the raw data your API has returned.

Saturday, June 18, 2016

Sencha Touch Create Dropdown Like Standard HTML Control

Recently in one of my project, we have a requirement to create dropdown like standard HTML dropdown with Sencha Touch. See the below screenshot.


As we know in Sencha Touch Selectfield (dropdown)  uses either floating panels and bottom picker to show and choose value from one. So in this blog I am going to mention how to do this. 

First of all following should be our views.

{
    xtype : 'panel',
    height: 40,
    itemId: 'monthSelector',
    id: 'monthSelector',
    style: 'background-color:#ffffff;color: #019297;border-bottom:1px solid #019297;font-size: 12px',
    html: '<div style="height:100%;width:100%;display: table;">$lt;div style="display: table-cell;vertical-align: middle;">Select Month</div><img style="position:relative;float:right;top:10px" height="20" width="20" src="resources/css/images/black-down-arrow.png"/></div>',
    listeners: {
         initialize: function( element ) {
               this.element.on({
                    tap: function( ele ){
                             MyApp.app.getController('MyController').toggleDropDown();
                    }
               });
         }
     }
},

{
xtype: 'dataview',
itemId: 'expenseMonthSelector',
id: 'expenseMonthSelector',
scrollable: false,
style: 'font-size: 12px',
height: 80,
store: {
fields: ['id', 'name','color'],
data: [
{id : 1, name: 'Current Month', color: '#9decf0'},
{id : 2, name: 'Previous Month', color: '#6cd2d6'}
]
},
itemTpl: '<div style="background-color: {color}; color:#000000;height:40px;width:100%;display: table;"><div style="display: table-cell;vertical-align: middle;padding-left: 20px">{name}</div></div>'
}

As you can see above we have one panel with layout look like a dropdown and one dataview which will act like options for the dropdown.

After this we will add our toggleDropDown function to toggle dropdown.

toggleDropDown: function(){
        if(this.getExpenseMonthSelector().isHidden() == true){
            this.getExpenseMonthSelector().show();
        }else{
            this.getExpenseMonthSelector().hide();
        }
},

Above code will simply show hide data view. Hope this helps you.