My passport has gone for police verification. What’s next?

The obvious answer is that wait for the local police station to call you. However, for how long and how to track its progress? I am here to throw some light on that.

Even if you have opted for SMS and email updates, passport department seldom sends any updates. The best source of finer status updates is login into their official portal from where you filled and submitted the application. Choose the same login and select the submitted application. You will notice an option to track status.

While it is with the local police for verification, the status here will say something like – It is sent for physical verification at XYZ station, and might take around three weeks. If you live in Hyderabad’s Cyberabad area then you can also track progress on the police side from http://verifast.in/cybStatusCheck.jsp.

This will provide info if they have received the request for processing or not. In our case we got a call from Cyberabad police after two days and then they came to our home for physical verification. They simply asked for the passport application form and related docs, and of course they physically met the applicant. Next day on the same portal we got info from the same portal that it has been processed by them and the report has been sent to RPO (Regional Passport Office). It does not specify the kind of report they have sent – Clear or Adverse. Adverse is bad, and might result into application rejection.

In a day or two the status on passport site should then change to something like – Report from XYZ police is under review at the RPO and if found clear, the passport would be sent for printing.

Finally after two three days if it updates to say something like – The passport has been sent for printing, then congratulations the police had sent clear report and your passport has been approved. After few more days again the new passport number and the Speed Post tracking number should be listed. At this point of time you should also receive an SMS for the same. In total the whole process took around 10 days.

If during this entire process if it looks like the process has got stuck somewhere, schedule an appointment for enquiry at the PSK from the official passport portal. All the best!

Starting OnePlus Android phone when its power button is broken

I have an ancient OnePlus 6 which my son uses for watching cartoon. Recently its power button stopped working and my son drained its battery until it shutdown. Fortunately its volume buttons are still working.

For this you will need a laptop and a USB-C cable to connect the phone with the laptop.

  1. Ensure the phone is charged.
  2. Remove the cable from the phone.
  3. Press the volume down button. Keep it pressed.
  4. While keeping the button pressed insert one of the of the cable into the phone and the other end in the charger or laptop or power bank.
  5. Still keep the volume button pressed until you see something on the screen. Then release the button.
  6. You will now get into phone’s recovery menu. Some versions of One Plus and other Android phones have restart option right here. If yes then choose that and you are done. – Else continue below –
  7. In my case; in OnePlus 6; I had to choose Advanced option and within that it had “Reboot to fastboot” and “Reboot to recovery mode”. Choose “Reboot to fastboot” here. But wait!
  8. First goto your laptop and install ADB tools from Google. Choose one from the following based on your laptop’s operating system.
  9. Extract the contents of the above zip file. Now choose the “Reboot to fastboot” option on your phone. Without this you will not able to turn on or off your phone until it runs out of battery since this mode requires the use of power button to confirm the selection.
  10. Connect the phone to the laptop using the cable then go into the extracted zip file’s directory and run ./fastboot devices to confirm that your phone is detected.
  11. Finally run ./fastboot reboot this will respond with a “Ok” response and your phone will reboot into normal mode. Congrats!

Deep dive into new tax regime of Budget 2020

Budget 2020 is a mixed bag and for the first time it provides the option to choose your tax slab. You have two slabs to choose from. The well understood old one and the new one. New one offers lower tax slabs but without any deductions (except for select few like 80CCD(2)).

There is nothing simple to having two slabs as option. Let’s compare the two and try to understand which one is better and under what circumstances.

Circumstance is the key word here; hence there are so many articles and videos which try to explain this using specific examples. I am not going into a specific case. But will use the power of graphs to plot all possible scenarios from income level 0 to 2Cr. This will hopefully provide some more insight into this mess.

In the below interactive chart the blue line is the tax amount (including applicable surcharge and 4% cess) as per the new slab. The orange line is the tax as per the old slab but without claiming any deductions. It is clear that purely slab-wise the new plan is lighter on tax. The jumps at 50L and 1Cr points are due to surcharges – 10% after 50L and 15% after 1Cr. Irrespective of that the tax as per new slab linearly increases similar to old slab while maintaining almost same difference.

See the Pen New vs Old Tax Comparision (data only) by Nirupam (@applegrew) on CodePen.

Interactive chart 1

From the graph above it might look like taxes from both slabs are exactly equidistant but if we zoom onto the green line at the bottom, we can see that it is not exactly that.

The difference increases as we move towards higher income. It is fixed after 15L slab. After that it increases in steps at 50L & 1Cr points.

What is clear is that as your income increase you need to claim more deductions to benefit from the old slabs.

Zooming into the portion before 15L shows a pretty unpredictable “wavy” difference. That means predicting if you will loose or gain if you use the new plan is much harder here. What is clear is that as your income increase you need to claim more deductions to benefit from the old slabs.

The below interactive chart shows the amount of deductions you need to claim in old slab to just match the tax benefits you get from new slab. In the topmost interactive chart this data is shown by red line near the bottom of the chart.

See the Pen Tax deductions comparision only (data only) by Nirupam (@applegrew) on CodePen.

Interactive chart 2

From 15L point it pretty fixed. You need to claim more than 2.5L of deductions to get benefit from old slab.

From 15L point it pretty fixed. You need to claim more than 2.5L of deductions to get benefit from old slab. If you cannot then switch to new slab. Out of 2.5L 50k Standard deduction you get for free, so what is left is 2L deduction. For that you need to max out your 80C, and NPS or 80D. If you have a home loan then it would be easier because you can claim 2L per annum of interest amount you paid for home loans. However, loans typically have more interest component towards the start and more principal amount at the end. To see how much interest you are paying year wise see – https://blog.applegrew.com/2019/01/calculating-amortisation-schedule-of-your-loans/.

The big dips after exact 50L and 1Cr points are due to surcharges. Even claiming a small deduction can bring your income to a slab where surcharge is zero or less, making your taxes match the gain in new slab. However, this lasts for approximate 4.5L range.

Let’s have a look at the range before 15L point more closely.

From 5L to 7.5L range the required deduction linearly increases from zero to 1.24L. So if you max out your 80C then that is good enough reason for you to keep using old slab.

From 7.5L to 10L range the rate of increase in required deduction amount lessens. At 10L point the required deduction is 1.88L. This plateaus out and continues until 12L point like that. Removing 50k, we are left with 1.38L deductions to fulfil. Here too if you just max out your 80C then old slab is great for you.

12L to 12.5L is one small range and then 12.5 to 15L range. The deduction for this range varies from 1.88L to 2.08L and 2.08L to 2.5L respectively. Here you need to pretty much max out 80C with NPS or 80D or should have home loans.

Finally

HRA is also one significant amount which I have not considered here. All in all figure out your gross income then use interactive chart 2 and locate your income level on x-axis. That should provide you with the min deduction amount you need claim to benefit from old slab. Add all your actual deductions and see if that fits the requirement.

However, even after the flat 50k deduction if you have the need to switch to new tax then you are not saving enough!

Addendum

Update1: I almost forgot about Standard deduction of 50k which you get in old slabs but not in new one. Updated the article accordingly.

Fix very low call volume on OnePlus 3

I recently faced this issue after a recent update on my OnePlus 3. The guide at – http://innov8tiv.com/fix-low-call-volume-oneplus-3t-calls/ is pretty good. However, the “Safe Mode” test failed for me, then next steps was clean with toothbrush.

I was very much convinced that my ear piece was pretty clean and anyway I wiped it with cloth many times and there was no visible dirt. However, when I took closeup picture of the earpiece I noticed that the grill mesh was very very small. And it seemed like maybe those tiny holes in the grill have been plugged by microscopic dirt.

Checkout the grill closeup below (this is after cleaning):-

I didn’t have a toothbrush with fine enough bristles. So instead I used a cotton swab, dipped in nail polish remover. I rubbed with that couple of times and presto, the low volume issue is fixed!

TIP: You need to tilt the handset sideways against the sunlight (as shown in the pic above) to be able to see the grill holes. If they look dark then the hole is open, else maybe they are plugged.

Tracing $scope events in AngularJS

Scope events in AngularJs is very powerful and useful in connecting disparate modules and directives. However, in a complex application things could become complicated and it would become hard to trace which event is triggered when and who act on those events.

I wrote a simple event tracer which displays a floating div with logs of all the events. The log is color coded, based on if the event was emitted, broadcasted or received.

The log looks like this:-

Event Trace

Event Trace

You can turn on or off the event data using the dataf link. The stackf toggles if the call stack or function code too will be shown which has emitted or consumed this event.

The code:-

var app = angular.module('tracer', []).run(Injector);

function Injector($rootScope) {
    'use strict';

    function log(msg, color) {
        var el = document.getElementById('tracerConsoleUl');
        el.innerHTML += itemHtml.format(color, msg)
    }

    function stringify(o) {
        try {
            return JSON.stringify(o, null, 3);
        } catch (err) {
            console.error('Scope Hack:', err, ' Actual object:', o);
            return '<i>Err: See console</i>';
        }
    }

    function getStackTrace() {
        var r;
        if (Error.captureStackTrace) {
            var obj = {};
            Error.captureStackTrace(obj, getStackTrace);
            r = obj.stack;
        } else if (Error.stack) {
            r = Error().stack;
        } else {
            r = '';
        }

        r = r.replace(/</gm, '&lt;').replace(/>/gm, '&gt;');
        r = r.replace(/^[^\s]+.+$/gm, ''); // removing first line
        r = r.replace(/^\s+at (.+) \([^(]+\)+$/gm, '$1');
        r = r.replace(/^\s+at [^()]+$/gm, ''); // removing rows with only text of format at ... and nothing in braces on right.
        r = r.replace(/\n\n/gm, '\n');
        r = r.replace(/\n/gm, ' &lt; ');

        return r;

    }

    function filter(e, clazz) {
        e.stopPropagation();
        e.preventDefault();

        var flag = angular.element('#tracerConsoleUl').hasClass(clazz);
        if (flag)
            angular.element('#tracerConsoleUl').removeClass(clazz);
        else
            angular.element('#tracerConsoleUl').addClass(clazz);
    }

    function fclear(e) {
        e.stopPropagation();
        e.preventDefault();

        angular.element('#tracerConsoleUl').empty();
    }

    function fmoveStart(e) {
        e.stopPropagation();
        e.preventDefault();

        angular.element(document).on('mousemove.scopehack', fmove).on('mouseup.scopehack', fmoveEnd);
        var el = angular.element('#tracerConsole');
        var left = e.pageX - parseInt(el.css('left'));
        var top = e.pageY - parseInt(el.css('top'));
        el.data('left', left);
        el.data('top', top);
    }

    function fmoveEnd(e) {
        e.stopPropagation();
        e.preventDefault();

        angular.element(document).off('.scopehack');
    }

    function fmove(e) {
        e.stopPropagation();
        e.preventDefault();

        var el = angular.element('#tracerConsole');

        var p = {
            left: (e.pageX - el.data('left')) + 'px',
            top: (e.pageY - el.data('top')) + 'px'
        };

        angular.element('#tracerConsole').css(p);

    }

    try {
        if (!String.prototype.format) {
            String.prototype.format = function() {

                var args = arguments;

                return this.replace(/{(\d+)}/g, function(match, number) {
                    return typeof args[number] != 'undefined' ? args[number] : '<i>NA</i>';
                });
            };

        }


        var html = "<div id='tracerConsole' style='position:absolute;top:50px;left:50px;background-color:white;border:2px solid black;z-index:1000;'>" +
            "<div><span class='ffilter' style='cursor:pointer;'>stackf</span> | <span class='dfilter' style='cursor:pointer;'>dataf</span> | <span class='fclear' style='cursor:pointer;'>clear</span> | <span class='fmove' style='cursor:move;'>move</span>" +
            "</div><ul id='tracerConsoleUl' style='display:block;list-style-type:none;max-height:500px;width:300px;overflow:scroll;'></ul></div>";



        var itemHtml = "<li style='border-bottom:1px solid gray;white-space:pre-wrap;background-color:{0};'>{1}</li>";

        var proto = Object.getPrototypeOf($rootScope);
        var oldOn = proto.$on;
        proto.$on = function mangaledOn(e, f) {
            var fWrapper = function fWrapper(e, d) {
                log('EVENT RECEIVED: {0} <span class="d">\nWITH DATA: {1}</span> <span class="f">\nBY f: {2}</span>'.format(e.name, stringify(d), f.toString()), '#7FD7B6');
                f.call(this, e, d);
            };

            oldOn.call(this, e, fWrapper);
        };

        var oldBroadcast = proto.$broadcast;
        proto.$broadcast = function mangaledBroadcast(e, d) {
            log('EVENT BROADCASTED: {0} <span class="d">\nWITH DATA: {1}</span> <span class="f">\nBY s: {2}</span>'.format(e, stringify(d), getStackTrace()), '#FF9C01');

            oldBroadcast.call(this, e, d);

        };

        var oldEmit = proto.$emit;
        proto.$emit = function mangaledEmit(e, d) {
            log('EVENT EMITTED: {0} <span class="d">\nWITH DATA: {1}</span> <span class="f">\nBY s: {2}</span>'.format(e, stringify(d), getStackTrace()), '#FFE78C');

            oldEmit.call(this, e, d);
        };

        console.log('Scope Hack Injected');
        angular.element('body')[0].innerHTML += html;
        angular.element('#tracerConsole .dfilter').on('click', function dfilter(e) {
            filter(e, 'dhide');
        });

        angular.element('#tracerConsole .ffilter').on('click', function ffilter(e) {
            filter(e, 'fhide');
        });
        angular.element('#tracerConsole .fclear').on('click', fclear);
        angular.element('#tracerConsole .fmove').on('mousedown', fmoveStart);
        angular.element(document).find('head').prepend('<style type="text/css">#tracerConsoleUl.dhide .d {display:none;}#tracerConsoleUl.fhide .f {display:none;} #tracerConsoleUl li{-moz-user-select:text;-webkit-user-select:text;-ms-user-select:text;}</style>');

    } catch (err) {
        console.error('Scope Hack:', err);
    }
}

To use this, paste this into some script block or some js file and make sure your app’s module depends on this module – tracer.

Using pinned self-signed SSL certificate with Android Volley

Recently for one of my Android apps I wanted to use a self-signed certificate on the server-side. However, if you try to connect to such a server with default settings, the connection is going to be refused. This is because it has been signed by you (your server domain), and ‘you’ is not trusted by any system.

Read the excellent article – Android security – Implementation of Self-signed SSL certificate for your App. This describes all the concepts and the pros and cons of pinning. However, it does not describe how to do this in Volley. The internet is littered with many articles on this, and most of them are outdated and can’t be used now.

So, here is an updated guide. I have tested this on my app which uses Android API 22 and Volley code downloaded on Jan 2015.

First use the official guide to create a singleton class to get the request queue. Now below is the modified code which takes care of the SSL pinning.

public class MySingleton {
    private static char[] KEYSTORE_PASSWORD = "YourKeyStorePass".toCharArray();

    ...

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            // getApplicationContext() is key, it keeps you from leaking the
            // Activity or BroadcastReceiver if someone passes one in.
            mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext(), new HurlStack(null, newSslSocketFactory()));
        }
        return mRequestQueue;
    }

    ...

    private SSLSocketFactory newSslSocketFactory() {
        try {
            // Get an instance of the Bouncy Castle KeyStore format
            KeyStore trusted = KeyStore.getInstance("BKS");
            // Get the raw resource, which contains the keystore with
            // your trusted certificates (root and any intermediate certs)
            InputStream in = mCtx.getApplicationContext().getResources().openRawResource(R.raw.codeprojectssl);
            try {
                // Initialize the keystore with the provided trusted certificates
                // Provide the password of the keystore
                trusted.load(in, KEYSTORE_PASSWORD);
            } finally {
                in.close();
            }

            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(trusted);

            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, tmf.getTrustManagers(), null);

            SSLSocketFactory sf = context.getSocketFactory();
            return sf;
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}

Please note, that the above solution will work for Android API 9 and above. To support the below versions you need to pass an instance of HttpClientStack instead of HurlStack. So, replacing the line

mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext(), new HurlStack(null, newSslSocketFactory()));

with

mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext(), new HttpClientStack(new MyHttpClient()));

might work. Where MyHttpClient is the one defined in the CodeProject article. I haven’t tested this part though.