Wednesday 21 June 2017

How to make a screen Recording app in Android - 100% Working Source code

Below is the source code for developing a screen Recording app.
NOTE: This code will work only for 21 and above api devices.

You can also watch video Click here

MainActivity.java
public class MainActivity extends AppCompatActivity
{
    private static final String TAG = "MainActivity";
    private static final int REQUEST_CODE = 1000;
    private int mScreenDensity;
    private MediaProjectionManager mProjectionManager;
    private static final int DISPLAY_WIDTH = 720;
    private static final int DISPLAY_HEIGHT = 1280;
    private MediaProjection mMediaProjection;
    private VirtualDisplay mVirtualDisplay;
    private MediaProjectionCallback mMediaProjectionCallback;
    private ToggleButton mToggleButton;
    private MediaRecorder mMediaRecorder;
    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
    private static final int REQUEST_PERMISSIONS = 10;

    static    {
        ORIENTATIONS.append(Surface.ROTATION_0, 90);
        ORIENTATIONS.append(Surface.ROTATION_90, 0);
        ORIENTATIONS.append(Surface.ROTATION_180, 270);
        ORIENTATIONS.append(Surface.ROTATION_270, 180);
    }

    @Override    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        mScreenDensity = metrics.densityDpi;

        mMediaRecorder = new MediaRecorder();

        mProjectionManager = (MediaProjectionManager) getSystemService
                (Context.MEDIA_PROJECTION_SERVICE);

        mToggleButton = (ToggleButton) findViewById(R.id.toggle);
        mToggleButton.setOnClickListener(new View.OnClickListener()
        {
            @Override            public void onClick(View v)
            {
                if (ContextCompat.checkSelfPermission(MainActivity.this,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE) + ContextCompat
                        .checkSelfPermission(MainActivity.this,
                                Manifest.permission.RECORD_AUDIO)
                        != PackageManager.PERMISSION_GRANTED)
                {
                    if (ActivityCompat.shouldShowRequestPermissionRationale                            (MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) ||
                            ActivityCompat.shouldShowRequestPermissionRationale                                    (MainActivity.this, Manifest.permission.RECORD_AUDIO))
                    {
                        mToggleButton.setChecked(false);
                        Snackbar.make(findViewById(android.R.id.content), R.string.label_permissions,
                                Snackbar.LENGTH_INDEFINITE).setAction("ENABLE",
                                new View.OnClickListener()
                                {
                                    @Override                                    public void onClick(View v)
                                    {
                                        ActivityCompat.requestPermissions(MainActivity.this,
                                                new String[]{Manifest.permission
                                                        .WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO},
                                                REQUEST_PERMISSIONS);
                                    }
                                }).show();
                    } else                    {
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission
                                        .WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO},
                                REQUEST_PERMISSIONS);
                    }
                } else                {
                    onToggleScreenShare(v);
                }
            }
        });
    }

    @Override    public void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        if (requestCode != REQUEST_CODE)
        {
            Log.e(TAG, "Unknown request code: " + requestCode);
            return;
        }
        if (resultCode != RESULT_OK)
        {
            Toast.makeText(this,
                    "Screen Cast Permission Denied", Toast.LENGTH_SHORT).show();
            mToggleButton.setChecked(false);
            return;
        }
        mMediaProjectionCallback = new MediaProjectionCallback();
        mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
        mMediaProjection.registerCallback(mMediaProjectionCallback, null);
        mVirtualDisplay = createVirtualDisplay();
        mMediaRecorder.start();
    }

    public void onToggleScreenShare(View view)
    {
        if (((ToggleButton) view).isChecked())
        {
            initRecorder();
            shareScreen();
        } else        {
            mMediaRecorder.stop();
            mMediaRecorder.reset();
            Log.v(TAG, "Stopping Recording");
            stopScreenSharing();
        }
    }

    private void shareScreen()
    {
        if (mMediaProjection == null)
        {
            startActivityForResult(mProjectionManager.createScreenCaptureIntent(), REQUEST_CODE);
            return;
        }
        mVirtualDisplay = createVirtualDisplay();
        mMediaRecorder.start();
    }

    private VirtualDisplay createVirtualDisplay()
    {
        return mMediaProjection.createVirtualDisplay("MainActivity",
                DISPLAY_WIDTH, DISPLAY_HEIGHT, mScreenDensity,
                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                mMediaRecorder.getSurface(), null, null);
    }

    private void initRecorder()
    {
        try        {
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
            mMediaRecorder.setOutputFile(Environment
                    .getExternalStoragePublicDirectory(Environment
                            .DIRECTORY_DOWNLOADS) + "/video.mp4");
            mMediaRecorder.setVideoSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);
            mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            mMediaRecorder.setVideoEncodingBitRate(512 * 1000);
            mMediaRecorder.setVideoFrameRate(30);
            int rotation = getWindowManager().getDefaultDisplay().getRotation();
            int orientation = ORIENTATIONS.get(rotation + 90);
            mMediaRecorder.setOrientationHint(orientation);
            mMediaRecorder.prepare();
        } catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    private class MediaProjectionCallback extends MediaProjection.Callback
    {
        @Override        public void onStop()
        {
            if (mToggleButton.isChecked())
            {
                mToggleButton.setChecked(false);
                mMediaRecorder.stop();
                mMediaRecorder.reset();
                Log.v(TAG, "Recording Stopped");
            }
            mMediaProjection = null;
            stopScreenSharing();
        }
    }

    private void stopScreenSharing()
    {
        if (mVirtualDisplay == null)
        {
            return;
        }
        mVirtualDisplay.release();
        destroyMediaProjection();
    }

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

    private void destroyMediaProjection()
    {
        if (mMediaProjection != null)
        {
            mMediaProjection.unregisterCallback(mMediaProjectionCallback);
            mMediaProjection.stop();
            mMediaProjection = null;
        }
        Log.i(TAG, "MediaProjection Stopped");
    }

    @Override    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String permissions[],
                                           @NonNull int[] grantResults)
    {
        switch (requestCode)
        {
            case REQUEST_PERMISSIONS:
            {
                if ((grantResults.length > 0) && (grantResults[0] +
                        grantResults[1]) == PackageManager.PERMISSION_GRANTED)
                {
                    onToggleScreenShare(mToggleButton);
                } else                {
                    mToggleButton.setChecked(false);
                    Snackbar.make(findViewById(android.R.id.content), R.string.label_permissions,
                            Snackbar.LENGTH_INDEFINITE).setAction("ENABLE",
                            new View.OnClickListener()
                            {
                                @Override                                public void onClick(View v)
                                {
                                    Intent intent = new Intent();
                                    intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                    intent.addCategory(Intent.CATEGORY_DEFAULT);
                                    intent.setData(Uri.parse("package:" + getPackageName()));
                                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                    intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
                                    intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                                    startActivity(intent);
                                }
                            }).show();
                }
                return;
            }
        }
    }
}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"                
xmlns:tools="http://schemas.android.com/tools"                
android:layout_width="match_parent"                
android:layout_height="match_parent"                
android:background="#FFFFFF"                
android:paddingBottom="@dimen/activity_vertical_margin"                
android:paddingLeft="@dimen/activity_horizontal_margin"                
android:paddingRight="@dimen/activity_horizontal_margin"                
android:paddingTop="@dimen/activity_vertical_margin"                
tools:context=".MainActivity">


    <TextView        
android:id="@+id/textView"        
android:layout_width="wrap_content"        
android:layout_height="wrap_content"       
android:layout_alignParentTop="true"        
android:layout_centerHorizontal="true"        
android:layout_marginTop="10dp"        
android:text="Recording Status: "        
android:textAppearance="?android:attr/textAppearanceLarge"/>

    <ToggleButton        
android:id="@+id/toggle"        
android:layout_width="wrap_content"        
android:layout_height="wrap_content"        
android:layout_below="@+id/textView"        
android:layout_centerHorizontal="true"        
android:layout_marginTop="5dp"        
android:text="Start"/>

    <ImageView        
android:id="@+id/imageView"        
android:layout_width="150dp"        
android:layout_height="150dp"        
android:layout_below="@+id/toggle"        
android:layout_centerHorizontal="true"        
android:layout_marginTop="85dp"        
android:src="@mipmap/icon"/>
</RelativeLayout>


string.xml
<resources>
    <string name="app_name">ScreenCapture</string>

    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>
    <string name="label_permissions">Please enable Microphone and Storage permissions.</string>
</resources>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?><manifest package="com.parambir.screencapture"          xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>

    <application        android:allowBackup="true"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme">
        <activity            android:name="com.parambir.screencapture.MainActivity"            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

build.gradle

apply plugin: 'com.android.application'
android {
    compileSdkVersion 24    buildToolsVersion "24.0.0"
    defaultConfig {
        applicationId "com.parambir.screencapture"        minSdkVersion 21        targetSdkVersion 24        versionCode 1        versionName "1.0"    }
    buildTypes {
        release {
            minifyEnabled false            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:24.0.0'    compile 'com.android.support:design:24.0.0'}

Note: Code refrence taken from https://github.com/Truiton/ScreenCapture


Saturday 3 June 2017

How to Resize ImageView by percentage in android - USING JAVA CODE

With every view, android provide an override method(onMeasure) in which there are 2 parameters(int widthMeasureSpec, int heightMeasureSpec), You can return height width according to your requirement. 
Example: If you want height = width means a square size view you can return height and width like this: 

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
    super.onMeasure(heightMeasureSpec, heightMeasureSpec);
}

You can create your custom view for this :

Example: 
Make a class names CustomImageView extends with ImageView
public class CustomImageView extends ImageView
{
    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(heightMeasureSpec, heightMeasureSpec);

        // you can set this as per percentage also. For example: "heightMeasureSpec * 50 /100"  ---- the height will be 50% of the view's width. 
    }
}

Use this in your layout like this :
<CustomImageView    
    android:id="@+id/imageView"    
    android:layout_width="match_parent"    
    android:layout_height="wrap_content"
    android:src="@drawable/ic_launcher"    />