Showing posts with label Android. Show all posts
Showing posts with label Android. Show all posts

Wednesday, 4 July 2018

Android material design colors

Background

When you creating an Android app from Android studio, studio pre-creates certain files for you. This includes the default style for the application. It looks something like below -


<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
</resources>

Now the question is what is this 
  • colorPrimary,
  • colorPrimaryDark and
  • colorAccent
These are all based on material design guidelines. For me, colors are as follows -

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
</resources>

But you can really choose any color theme you want. For more details, you can see google documentation -

In this post, I will list what each color naming means.


Android material design colors

Following are naming conventions used -

  • colorPrimary:  The color of the app bar.
  • colorPrimaryDark: The color of the status bar and contextual app bars; this is normally a dark version of colorPrimary.
  • colorAccent: The color of UI controls such as checkboxes, radio buttons, and edit text boxes.
  • windowBackground: The color of the screen background.
  • textColorPrimary: The color of UI text in the app bar.
  • statusBarColor: The color of the status bar.
  • navigationBarColor: The color of the navigation bar.


To visualize refer to the following picture -





You can create and preview your colors here -> https://www.materialpalette.com/


Related Links

Thursday, 5 April 2018

How to use a file to store all your logs in Xamrin Android App

Background

You can see the debug logs in the Device Log tab in Visual studio but you need to connect a USB to your android phone (not needed if you are using an emulator). However this is for realtime debugging and will not be useful to check logs that were present couple of hours back. In this post I will show you how you can log into a file in the android sd card so that you can refer it at any point in time to see what has happened.


How to use a file to store all your logs in Xamrin Android App

You can log to a file using following code snippet -

using System;
namespace Com.Osfg
{
    public class LogUtils
    {
        String logFilePath = null;

        public LogUtils()
        {
            String path = Android.OS.Environment.ExternalStorageDirectory.Path;
            logFilePath = System.IO.Path.Combine(path, "log.txt");
            if(!System.IO.File.Exists(logFilePath))
            {
                using (System.IO.StreamWriter writer = new System.IO.StreamWriter(logFilePath, true))
                {
                    writer.WriteLine("Starting logging at " + DateTime.Now.ToString());
                }
            }
        }

        public void Log(String message)
        {
            using (System.IO.StreamWriter writer = new System.IO.StreamWriter(logFilePath, true))
            {
                writer.WriteLine(DateTime.Now.ToString() + " : " + message);
            }
        }
    }
}

Let's uderstand whats happening here -

In the constructor we are getting the external storage directory and creating a file called "log.txt" there. We are checking if the file already exists and if it does not we create it. Now anyone who want to log to this file can simple create an instance of LogUtils and call Log method on it.

You can do this on OnCreate of your main activity. For me external storage file is - /storage/emulated/0 so my complete log file path is /storage/emulated/0/log.txt

Make sure you have provided appropriate permissions in the manifest file -

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


Related Links



Friday, 30 March 2018

Hello World Xamrin Android project tutorial

Background

Xamrin are set of tools built on .NET framework . It allows you to develop applications for Android, iOS and Windows using C# language and the .NET framework.In this post I am going to show you how to develop a native android application using xamrin.

Setup

For this tutorial you need to have Visual Studio with Xamrin components installed on your Windows operating system. You can get it from Visual Studio installer. Or from Visual Studio you can go to Tools -> Get Tools and Features.


 Hello World Xamrin Android project tutorial

Click on File -> New Project  and choose Blank App(Android)

 One you have created the project you should see following code structure -


 Let's go over some of the important files here -
  1. MainActivity.cs : This is your main launcher activity.
  2. Resources/layout/Main.axml : This is your launcher ctivity layout file
  3. Resources/values/String.xml : This is your string resource file.
Go to  Resources/layout/Main.axml and add a EditText and a Button to the Linear Layout that you have. You can do that from  Designer mode with just drag and drop.



Change the id of EditText and Button to "helloWorldeditText" and "ckickMeButton" respectively. So your source would look like -

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/helloWorldeditText"
        android:text="Hello World!" />
    <Button
        android:text="Click Me!"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/ckickMeButton" />
</LinearLayout>
Now go to MainActivity.cs and make following changes. We are basically going to implement a button and  change the text of EditText on the click of the button.
using Android.App;
using Android.Widget;
using Android.OS;

namespace AndroidDemo
{
    [Activity(Label = "AndroidDemo", MainLauncher = true)]
    public class MainActivity : Activity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);
            EditText helloWorldEditText = FindViewById<EditText>(Resource.Id.helloWorldeditText);
            Button clickButton = FindViewById<Button>(Resource.Id.ckickMeButton);
            helloWorldEditText.Text = "Hello World!";
            clickButton.Click += delegate { helloWorldEditText.Text = "Button Clicked!"; };
        }
    }
}



Notice the resource IDs we changed and use to reference it in the code. And that's it. Just deploy the code to an android device or an emulator and test our changes.





Related Links




Friday, 15 December 2017

Fixing 'Error:Unsupported method: BaseConfig.getApplicationIdSuffix()' issue in Android Studio

Background

I tried importing an old android project into my Android Studio and the build was failing with following error -

Error:Unsupported method: BaseConfig.getApplicationIdSuffix().
The version of Gradle you connect to does not support that method.
To resolve the problem you can change/upgrade the target version of Gradle you connect to.
Alternatively, you can ignore this exception and read other information from the model.




Solution

As the error itself says solution is to upgrade gradle version.

Go to project level build.gradle. For me it looks like below -

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.2.3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}


Just upgrade the gradle version from 1.2.3 (or whatever you have)  to 3.0.1. You can try upgrading to other higher versions as well. This is what worked for me. So the build.gradle looks like below -

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}




Once you do that click on "Try again" and the gradle sync should go through.



Sunday, 22 October 2017

How to enable hidden night mode setting on your Android N device

Background

Everyone likes the night mode settings. It puts less strain on your eye. You must have used f.lux on your PC or laptop. Google's Pixel phones have this feature where you can just toggle night mode. However other models don't. There might be vendor specific feature as well. Like some Samsung models might offer this. 

Night mode was provided in hidden System UI tuner section in the beta build of Android N and was completely removed in the final build. However code still resides in the build and can be turned on. It is not that easy though. And this is exactly what we will see. 

NOTE : This feature was altogether removed on Android 7.1 so below workaround will only work with android 7.0 Android N.


How to check if I have Android N 7.0?

Go to Settings -> About Phone -> Android Version

You should see 7.0 there. You can also tap it 3 time to see a nice Animation of Android N.





How to enable hidden night mode setting on your Android N device

First we need to turn on the hidden System UI tuner.
  • Pull down the notification tray twice and you should see the settings shortcut (cog icon). Long press it and release. You should see a toast message saying System UI Tuner has been added to settings. You should also start seeing wrench icon beside the cog icon indicated the UI Tuner has been enabled.








  • You can now simply toggle to set night mode automatically based on device time.  You can also optionally allow to change brightness as well.




  •  Lastly night mode setting should now be present in your notification tray as well for quick access and toggle.



 This approach worked fine for me. Let me know if you face issues.

Sunday, 6 August 2017

Enabling Eclipse key map/shortcuts in Android Studio

Background

If you are from a developer using Eclipse then when you start using Android Studio then it becomes difficult to learn new shortcuts. For such cases Android Studio provides an option to use Eclipse shortcuts and in this post we will see how.

Enabling Eclipse key map/shortcuts in Android Studio

Go to 
  • Android Studio -> Preferences
Type in keymap in the searchbox. You should be able to see a keymap section -



Next select Eclipse or Eclipse(Mac OS X) whichever you are more comfortable with. Then click Apply and Ok.



You should be good to use Eclipse shortcuts now. No need to restart.


Related Links


Saturday, 29 April 2017

Setting up Unity platform to build android games

Background

This tutorial assumes you have already installed Unity.
You can download Unity from their official site - https://unity3d.com/
In this post we will see how to setup Unity to test android games that you develop.

For details you can visit their site - https://unity3d.com/
and you can also see list of games that are already created with Unity. So lets get started -

Setting up android build setup in Unity

Fire up your Unity. Once it is opened you can create a new project and add a new scene to it. It's like creating project in any IDE. Once Unity is up and running go to 
  • File -> Build Settings
 Then
  1. Select android as the platform
  2. Click Switch platform
  3. Click Add Open scenes - this should add all open scenes in build setting
  4. Finally click on build (This step will generate your android apk file. Skip this step if you are doing 1st time well come to this in a moment. Before this we need to have some more configurations.)


 Also you can see Player setting right besides switch platforms. Click this to open a new section of player settings. Here you will see settings that are specific to your android app. If you are developed android apps before then you would know it requires app/bundle id, app icon of different resolutions, app name, api version to build your app, certificate to sign your app for production build etc. all of this you can configure in this section.




 Next you need to tell Unity location of your Android SDK and JDK.  For this go to
  • Unity -> preferences.
This path will be different based on your operating System. For me it's Mac so preferences are in Unity -> Preferences. If you have windows it can be in File -> Preferences.

Once preferences window is opened go to External tools and provide path of your Android SDK and JDK as shown in screenshot below -



 After this your unity is all setup to create and run your android app. Lets see how we can test this setup.

Testing remote android apps

For testing Unity has provided an android app that you need to install on your android device. Before that make sure -
  • Your device has developer mode enabled and have enabled USB debugging
  • It is connected to your machine running Unity with USb cable.
Then you can install unity remote on your device -

Latest one when I am writing this post is unity remote 5. Check accordingly.

Once you have installed it go to Unity on your machine . Now go to
  • Edit -> Project Settings -> Editor
and select Any android device as device.



 That's it. You can just play and you can see your scene running in android unity remote app.

Following are screenshots in playmode from my laptop and android device running unity remote -






Enjoy :)

Related Links

Wednesday, 12 April 2017

Using HttpUrlConnection in Android

Background

Android has two options for doing network operations using Http clients -
  1. Apache HttpClient
    1. DefaultHttpClient
    2. AndroidHttpClient
  2. HttpUrlConnection


Back in 2011 Android developers announced that Android team is not actively working on Apache HTTP Client and that  new android applications should use HttpURLConnection and that is where they will be spending their energy going forward.

For more details you can read their blog -  Android’s HTTP Clients 

It's been a long way since they has posted that post and here we are. Android Http client was totally removed from Android 6.0 (M). Ofcourse you can manually plug it in. But android developer site says the following -

Android 6.0 release removes support for the Apache HTTP client. If your app is using this client and targets Android 2.3 (API level 9) or higher, use the HttpURLConnection class instead. This API is more efficient because it reduces network use through transparent compression and response caching, and minimizes power consumption. To continue using the Apache HTTP APIs, you must first declare the following compile-time dependency in your build.gradle file:

android {
    useLibrary 'org.apache.http.legacy'
}


But I would recommend don't do this unless some legacy API needs this. Move on to HttpUrlConenction. In this post we will see how we can use HttpUrlConnection for network operations in android.

Using HttpUrlConnection in Android

HttpURLConnection is a general-purpose, lightweight HTTP client suitable for most applications. A simple snippet would be- 

        URL url = new URL("http://google.com");
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setRequestMethod("GET");
        try {
            InputStream in = new BufferedInputStream(urlConnection.getInputStream());
            readStream(in);
        } finally {
            urlConnection.disconnect();
        }

So you open a connection by calling openConnection() on an URL instance. You can then set the type of request using setRequestMethod(). It can be GET, POST etc. Then you read the stream by calling urlConnection.getInputStream(). Finally you call disconnect() to release your connection.


NOTE : By default HttpUrlConnection will use GET as request type i.e you dont have to mention  urlConnection.setRequestMethod("GET"); . For others as started above you can use - setRequestMethod();

NOTE :  Connection is actually established when you call getInputStream() or getOutputStream() or getResponseCode() on your httpUrlConenction instance.

NOTE : If your response is not 2** then it would be an error(You can read the response code by calling getResponseCode() method). In that case you need tor read error stream. You can do that by using getErrorStream() to read the error response. The headers can be read in the normal way using getHeaderFields().
 

How disconnect() works?

    Each HttpURLConnection instance is used to make a single request but the underlying network connection to the HTTP server may be transparently shared by other instances. Calling the close() methods on the InputStream or OutputStream of an HttpURLConnection after a request may free network resources associated with this instance but has no effect on any shared persistent connection. Calling the disconnect() method may close the underlying socket if a persistent connection is otherwise idle at that time.   

 -> So basically your HttpUrlConnection instance may get GCed but the underlying TCP socket will get pooled and reused unless you call disconnect() on it in which case it may or may not close the socket. So if you are not reconnecting to same URL it is safe to always call disconnect and let android handle the socket pooling and closing part.

Android docs clearly states -  Disconnecting releases the resources held by a connection so they may be closed or reused.

Handling request body

Sometime a request made to a server may need a request body to be supplied. For that you can use the httpUrlConnection instance's outputStream.

        URL url = new URL("http://test.com");
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setRequestMethod("POST");
        urlConnection.setDoOutput(true);
        urlConnection.setChunkedStreamingMode(0);
        try {
            OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
            writeStream(out);

            InputStream in = new BufferedInputStream(urlConnection.getInputStream());
            readStream(in);
        } finally {
            urlConnection.disconnect();
        }

Make sure you set setDoOutput(true) if you have request body to be sent. Similarly set setDoInput(true) if you are reading back from the connenction. If you just want to see response code using - getResponseCode() method that these are not required.

NOTE : Notice how we have use BufferedStreams over input/output streams. They are used for performance reasons - so that data is buffered and we can easily read/write it.

Setting headers and connection timeouts

If you are familiar with HttpClient then you must have set connection and socket timeouts. In HttpUrlConenction you need to do following -

        urlConnection.setConnectTimeout(30000);
        urlConnection.setReadTimeout(30000);

These are in milliseconds. I have set it to half a minute above. To set headers in the request you can do -

urlConnection.setRequestProperty("headerName", "headerValue");

So lets say you want to set user-agent in your request you do -

urlConnection.setRequestProperty("User-Agent", "Mozilla");

Similarly you can enable disable redirects using -
urlConnection.setInstanceFollowRedirects(false);

Making secure connection (https)

If you are working with https (secure connection) protocol then your actual class would be - HttpsUrlConnection.

NOTE :  You can still use HttpUrlConnection since HttpUrlConenction extends HttpsURLConnection (by polymorphism).

HttpsUrlConnection will allow you to override HostnameVerifier and SSLSocketFactory.

Eg.

static {
    TrustManager[] trustAllCertificates = new TrustManager[] {
        new X509TrustManager() {
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null; // Not relevant.
            }
            @Override
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
                // Do nothing. Just allow them all.
            }
            @Override
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
                // Do nothing. Just allow them all.
            }
        }
    };

    HostnameVerifier trustAllHostnames = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true; // Just allow them all.
        }
    };

    try {
        System.setProperty("jsse.enableSNIExtension", "false");
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCertificates, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(trustAllHostnames);
    }
    catch (GeneralSecurityException e) {
        throw new ExceptionInInitializerError(e);
    }


Sample take from this SO discussion.

NOTE :   Calling HttpsURLConnection.setDefaultSSLSocketFactory() or HttpsURLConnection.setDefaultHostnameVerifier() will set it up for all Https connections. If you want to set it for specific connections then type cast it to HttpsUrlConenction instance and then call set methods on it.

Handling multipart/ form-data

 You'd normally use multipart/form-data encoding for mixed POST content (binary and character data). The encoding is in more detail described in RFC2388.

String param = "value";
File textFile = new File("/path/to/file.txt");
File binaryFile = new File("/path/to/file.bin");
String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.
String CRLF = "\r\n"; // Line separator required by multipart/form-data.
URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

try (
    OutputStream output = connection.getOutputStream();
    PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, charset), true);
) {
    // Send normal param.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"param\"").append(CRLF);
    writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
    writer.append(CRLF).append(param).append(CRLF).flush();

    // Send text file.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"textFile\"; filename=\"" + textFile.getName() + "\"").append(CRLF);
    writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF); // Text file itself must be saved in this charset!
    writer.append(CRLF).flush();
    Files.copy(textFile.toPath(), output);
    output.flush(); // Important before continuing with writer!
    writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary.

    // Send binary file.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" + binaryFile.getName() + "\"").append(CRLF);
    writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(binaryFile.getName())).append(CRLF);
    writer.append("Content-Transfer-Encoding: binary").append(CRLF);
    writer.append(CRLF).flush();
    Files.copy(binaryFile.toPath(), output);
    output.flush(); // Important before continuing with writer!
    writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary.

    // End of multipart/form-data.
    writer.append("--" + boundary + "--").append(CRLF).flush();

Again code is taken from this SO discussion.

Other advantages of using HttpUrlConnection

  • HttpUrlConnection by default honors system proxy. However if you want to specify a custom proxy then you can do so with API - url.openConnection(proxy)
  • It also has transparent response compression. It will automatically add the header - Accept-Encoding: gzip to outgoing responses and also handle it automatically for incoming connections.
  •  It also attempts to connect with Server Name Indication (SNI) which allows multiple HTTPS hosts to share an IP address.

Related Links

Sunday, 2 April 2017

Android material design floating labels on EditText and Password visibility Toggle

Background

With android design support library new element - TextInputLayout was introduced. With this we can totally omit static labels that we put before text input elements (EditText for example). With this label will float on the top of the EditText when user focuses on that field for entering data. Also we can show error on the same field post validation. That gets show floating below the EditText. It also has passwordToggleEnabled   which lets you toggle the visibility of your password field with an eye icon (it can be customized to use a different icon too). We will see all of these in this post.

Android material design floating labels on EditText and Password visibility Toggle

Make sure your app level gradle has following dependencies added -

    compile 'com.android.support:appcompat-v7:25.1.1'
    compile 'com.android.support:design:25.3.1'

NOTE : Base version of you appcompat and your design library should be same. For eg. it's 25 for this case.

Next lets go straight to the layout. The feature that we are looking for goes something like this -

        <android.support.design.widget.TextInputLayout
            android:id="@+id/input_layout_password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
 app:passwordToggleContentDescription="@string/passwordToggleContentDescription"
            app:passwordToggleEnabled="true"
            app:passwordToggleTint="@color/colorAccent">

            <EditText
                android:id="@+id/input_password"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/hint_password"
                android:inputType="textPassword"/>

        </android.support.design.widget.TextInputLayout>



Now I have combined both floating labels and password toggle in a single example. Lets see how it works now.

  • First of all you need to wrap  EditText element inside TextInputLayout element. 
  • Next android:hint value of EditText will come out on top as a floating label.
  • For password visibility to be toggle we need to provide app:passwordToggleEnabled="true" attribute. Others are optional really. Lets see what all attributes it supports.

  1.  passwordToggleEnabled : allows you choose whether or not you want the password visibility to be toggled.
  2. passwordToggleContentDescription :  allows a string to be set for the content description. This is used for accessibility feature.
  3. passwordToggleDrawable : allows one set a different icon other than the default visibility toggle icon (eye icon). 
  4. passwordToggleTint : allows the visibility toggle icon to be tinted to whatever colors you indicate.
  5. passwordToggleTintMode : sets the blending mode used to apply the background tint.
You can see the complete specs in android developers site. It would look like below -








Final screen is just showing a toast when you press login and all validations have gone though successfully.Speaking of validation lets come to it.

Do not worry about the minute code details like string resources. You can find the complete code on my github repo -
Lets just focus on concepts for now.

We said in our initial discussion that TextInputLayout can handle errors as well and they are shown floating just below the EditText. Lets look at the code for it.

  1. In your activity's onCreate() method get a reference to the TextInputLayout element and reference to the EditText wrapped in it.
  2. Next you can addTextChangedListener() to your EditText and do validations there.
  3. To set and display an error you simply need to call setError()on textInputLayout element. To remove error you can simply call setErrorEnabled(false).
Lets see how we can do it in case of our Email field. First of all get a reference to TextInputLayout and the EditeText in it -

        inputLayoutEmail = (TextInputLayout) findViewById(R.id.input_layout_email);

        inputEmail = (EditText) findViewById(R.id.input_email);


Next add addTextChangedListener to inputEmail and in it's afterTextChanged() method simply do your validations. In this case we are just calling a private validate method from afterTextChanged() method as follows -

    private boolean validateEmail(String text) {
        if(!isValidEmail(text)) {
            inputLayoutEmail.setError(getString(R.string.error_email));
            inputEmail.requestFocus();
            return false;
        }
        else {
            inputLayoutEmail.setErrorEnabled(false);
        }
        return true;
    }



    private boolean isValidEmail(String email) {
        return !TextUtils.isEmpty(email) && android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches();
    }


and you are done. You should see error as shown in following screenshots -




Again for complete code please refer to my github repo -

Related Links



Saturday, 1 April 2017

Android : URI is not registered (Settings | Project Settings | Schemas and DTDs)

Background

When you are developing android application you might sometime see following error on your layouts xml files in Android studio-
  • URI is not registered (Settings | Project Settings | Schemas and DTDs)


Everything seems correct except this error is persistent. Gradle sync works fine too. Lets see how we can resolve this.

Solution

  • Before we see how to resolve this issue make your layout file is in correct directory structure. It should be under layout folder which would be under res folder.




  • Now look at build variant tab at the bottom left of android Studio. You should see the current version set. It could be -
    • debug OR
    • release
In my case it was release. Just switch the version and then switch it back. In my case I switched it to release and then back to debug and the error was gone.


  •  If above 2 methods did not work out for you then Close all open tabs and reopen them. 
  • Last but not the least - restart Android Studio.
I know these are just silly workaround. Let me know which one works for you :)

 

Sunday, 19 March 2017

Creating a new Xposed module in Android

How Xposed works

Before we start lets see how Xposed works -

There is a process that is called "Zygote". This is the heart of the Android runtime. Every application is started as a copy ("fork") of it. This process is started by an /init.rc script when the phone is booted. The process start is done with /system/bin/app_process, which loads the needed classes and invokes the initialization methods.

This is where Xposed comes into play. When you install the framework, an extended app_process executable is copied to /system/bin. This extended startup process adds an additional jar to the classpath and calls methods from there at certain places. For instance, just after the VM has been created, even before the main method of Zygote has been called. And inside that method, we are part of Zygote and can act in its context.

The jar is located at /data/data/de.robv.android.xposed.installer/bin/XposedBridge.jar and its source code can be found here. Looking at the class XposedBridge, you can see the main method. This is what I wrote about above, this gets called in the very beginning of the process. Some initializations are done there and also the modules are loaded.

Creating a new Xposed module in Android

I have couple of app on playstore . I am going to use FlashLight to demonstrate Xposed module.

  • Create a normal Android app. Add following extra meta data in the apps manifest file. This is how xposed installer app knows your apk is a xposed module.

        <meta-data
            android:name="xposedmodule"
            android:value="true" />
        <meta-data
            android:name="xposeddescription"
            android:value="Demo example that renders Flashlight app (com.osfg.flashlight) useless" />
        <meta-data
            android:name="xposedminversion"
            android:value="53" />

  • Next create a class that implements IXposedHookLoadPackage like below -

public class XPFlashLightKiller implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {

        if (!loadPackageParam.packageName.equals("com.osfg.flashlight"))
            return;

        XposedBridge.log("Loaded app: " + loadPackageParam.packageName);

        XposedHelpers.findAndHookMethod("com.osfg.flashlight.FlashLightActivity", loadPackageParam.classLoader, "isFlashSupported", new XC_MethodHook() {
            @Override
            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                // this will be called before the clock was updated by the original method
            }
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                // this will be called after the clock was updated by the original method
                XposedBridge.log("Hooken method isFlashSupported of class com.osfg.flashlight.FlashLightActivity");
                param.setResult(false);
            }
        });
    }
}

NOTE :  Here we have used XC_MethodHook as callback so that we can execute methods before and after original method is executed. Other alternative is to replace the original method entirely - original hooked method will never get executed.

When you call XposedHelpers.findAndHookMethod the callback can either be
  • XC_MethodHook : Callback class for method hooks. Usually, anonymous subclasses of this class are created which override beforeHookedMethod(XC_MethodHook.MethodHookParam) and/or afterHookedMethod(XC_MethodHook.MethodHookParam).
  • XC_MethodReplacement : A special case of XC_MethodHook which completely replaces the original method.

1st one just provides you the hooks to execute methods before and after original method where as 2nd one replaces it completely.

  • Next create a file called xposed_init in your assets folder and add your fully qualified class name to it. This file tells xposed installer where to look for the module class. For eg in our case it will be -
com.osfg.flashlightxpmodule.XPFlashLightKiller


  • Finally download XposedbridgeApi.jar from here and add it in your app folder. Make sure the version of this jar should be same as xposedminversion set in the meta data tags in step 1.
Now build your app and deploy on your device. Once done Xposed installed should detect it. Just enable the module and reboot the device -



Testing out the module


Just to give you some background on the original Flashlight app. It's code is something like below -

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
    {
        switch (requestCode)
        {
            case CAMERA_PERMISSION:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.d(TAG, "Received Camera permission");
                    if(!isFlashSupported()) {
                        Toast.makeText(getApplicationContext(), "LED Flash is not supported on your device",Toast.LENGTH_LONG).show();
                        finish();
                    }

                }
                else {
                    Log.d(TAG, "Camera permission denied");
                    Toast.makeText(this, "Please provide camera permission", Toast.LENGTH_SHORT).show();
                    finish();
                }
                return;
        }
    }



It first asks for permission. If you give it then it will check if flash is supported on the device. So if you have already given Flashlight app camera permission then remove it from settings and open the app again. Now when it prompts for permissions again give it. But now you can see that the app shuts down with toast message - "Flash not supported on this device". This is because we hooked into isFlashSupported() method and made it always return false. So that the app never works :)

NOTE : From next time it will work fine. Since permission is already given next time it will not prompt and never execute  isFlashSupported() method. To retest remove the permissions from settings again.





You can also see following line in logcat -

03-20 02:36:37.864 8002-8002/? I/Xposed: Loaded app: com.osfg.flashlight

03-20 02:36:44.123 8002-8002/? I/Xposed: Hooken method isFlashSupported of class com.osfg.flashlight.FlashLightActivity


Complete code is added in my github repo -

Related Links


Installing Xposed Framework on Android devices

Background

Android as you know is very flexible and developer friendly. It runs a Linux kernel underneath with some modifications needed to operate handheld devices with relatively less memory. You can root your device to further boost its potential application. You can do stuff with root access now. You can even take it a step further - Unlock boot-loader and install customer recovery like ClockworkMod or TWRP (We are going to work with TWRP in this post). Custom recovery software's let you install custom mods or even full ROMs that can drastically improve user experience.

Xposed is a framework that can alter the the way your applications work, give you more control over it without actually flashing any custom ROMs or MODs or even tampering any of the apks. It uses root privileges to access androids core resources and use it to change the androids behavior .It's potential power is unlimited. We will see how to install and use it in a while.

NOTE : Xposed uses root privileges i.e device needs to be rooted.

Xposed is a framework once installed you can create and install various modules to alter apps/android behavior. Best part about this is that the modules are held in memory. So to get back the system to original state all you need to do is uninstall the module and reboot the device.




NOTE : Works on Android 4.0.3 (ICS) and above only.

Xposed framework is brought to us by XDA Recognized Developer rovo89.

Warning : This required rooting your device and changing some androids base resources. Follow this guide on your own risk. We are not liable if you phone gets bricked or damaged in the process.

 Installation and Setup

Make sure your device is recognized by adb (connect your device to your laptop having android SDK using a USB) -


NOTE : If you adb is not able to detect or recognize your device then you may refer to link in the Related Section at the end of this post.

Before you start Xposed has two parts to it -
  1. Xposed Framework : Lays down all the groundwork for the framework
  2. Xposed Installer app : Apk use to manage Xposed modules.
Download the framework from -
Choose based on your the sdk version you have on your android device.

You can download the latest xposed installer from  -
First we are going to flash custom recovery image - TWRP on our Android device. So first reboot in bootloader mode using following command -
  • adb reboot bootloader
You device should reboot now and you should see following screen -


Once you reach above screen adb will not work. You need to use fastboot instead. You can type following command to make sure your device is still connected -
  • fastboot devices



 Now lets flash our recovery image. Use following commands to do so -
  • fastboot flash recovery /Users/athakur/Desktop/xposed/twrp-3.0.2-0-hammerhead.ndif
 You can download the image from here. Above command obviously has path to the image from my local machine. You need to replace it accordingly.



Once done navigate to Recovery mode by navigating using vol up/down button. Once on Recovery mode press power button to enter it.




Now go to install and install the Xposed framework - the zip file we downloaded earlier and then reboot.




On reboot install the Xposed installed apk. On install open it -




Here your Xposed  setup and installation is complete. You can create and install modules going in Modules section of installer as shown in screenshots above. We will see how to create modules in upcoming post. So stay tuned!

Good to Know 

What is Fastboot? : Fastboot is a protocol that can be used to re-flash partitions on your android device (update the flash file system in your Android devices). It comes with the Android SDK (Software Developer Kit) and can be user as an alternative to the Recovery Mode for doing installations and updates.

What is Android recovery image? : A bootable program on an Android flash memory partition (/recovery) that is used to perform a factory reset or restore the original OS version. You can also install a different OS version (a different ROM). For that the stock recovery image must be replaced with a custom version such as ClockworkMod Recovery or TWRP (as we are doing).

Related Links


t> UA-39527780-1 back to top