sábado, 17 de octubre de 2020

Android Alebrijes - Dealing with legacy code.

Alebrijes are brightly colored Mexican folk art sculptures of fantastical creatures. Alebrijes are very strange and unknown animals.

A new user story comes for grooming, apparently a very small change, but as part of the requirements you have to change the legacy class, yes that class that no one wants to touch and everyone is scared of, sounds familiar? After reading the story, everyone agreed on 3 points, you think you can do it faster, but you want to be cautious so you say 3.

When the sprint starts you are very excited to do the change, you open the code, and boom, you found an alebrije. What the falafal is going on here?, this story requires more things than I initially thought, how I will be able to finish this? and I’m not even able to understand the code.

Wait, how did we end up with this implementation? Why the code is written in this way? Ummm, there are multiple reasons why this piece of falafal ended up like this, but now is not the time to find a culprit; as one of my managers use to say, “you touch it, you own it” or “Es tu perro y tu lo bañas”, now you are the owner of this code and you are responsible for this.

Let’s be honest, every single project around has code like this, a lot of code is already a mess, and we need to learn how to live with it, so the real question is what can we do to make it better? How can we improve the quality of this code?

Every situation is different, and there is no silver bullet to deal with this mythical beasts, but let’s start with the premise that you got a very old piece of code with zero documentation, zero unit testing, and not following the architecture patterns, conventions and best practices for Android. With that in mind here are some of the things that you can do:

Improving Documentation 

How much documentation do we need? Only whatever you can keep updated. Keep it simple, but not too simple. Add enough detail to understand how the implementation works.

Start by creating a simple diagram. It can be a simple diagram with boxes and their relationships. This will help to understand what components are involved. If the authors of the code are still available, involve them.

After the basic diagram, you can create a navigation flow, a high-level class diagram, and sequence diagrams to understand the flow, dependencies, behaviors, and responsibilities of each component.

When the feature includes complex business logic, use the Debugger and logger to understand it better. Document all your findings.

Start documenting the code

  • Public methods. Start with public methods. Those are the ones expose to external invokers and require good documentation.
  • Exceptions. Document possible exceptions to be thrown by methods.
  • Executable specifications through unit testing. This will continuously increase with each iteration. Try to follow a pattern where we clearly specify the scenarios under test and the expected behavior. One popular naming convention Should_ExpectedBehavior_When_StateUnderTest.

Make a list of to-do items to improve the code. TODOs can be included in the code or using some wiki page. Next time someone has some free time, they can come to the list and pick one of the items.

Improving Estimation

Don’t shout yourself in the foot, be prepared ahead of the grooming. You need enough time to work on legacy code. We need to be as accurate as possible. We don’t want to introduce more technical debt or make the code worst.

Start by reading and understanding the user story.

Identify the changes needed to accomplish the new functionality.

When the story has a big impact on the code, split it into small to-do tasks.

Estimate the required tech tasks to complete the user story. Don’t forget to include integration testing or data preparation when needed.

Improving Testing

Without tests, there is no way to tell if we are breaking existing functionality. Don’t trust code, not including tests.

But where do I start if most of the code is in the views, in private methods, static functions, and final classes?

Robolectric

Robolectric lets you run view tests without an emulator or physical device. This will help you to write tests for the views without installing the app. You can test activities or fragments in isolation. Robolectric extends Android framework with a large set of test APIs. Robolectric uses the concept of shadows to extend the behavior of an Android OS component. You can create your own custom shadow implementations.

Kotlin and Mockk

With the help of Kotlin and Mockk you should be able to test static utility methods, static initializers, final classes, private methods. Powerbock is a really good option if you are allowed to use only java.

Improving the code Quality

We can start with small refactors to improve the readability and maintainability of the code. We can start with changes like renaming classes, variables, and methods. This will help us to get a better understanding of the implementation so we can proceed with bigger refactors.

Please make small PRs when making your changes. If you send a big PR, is very likely that reviewers will not be able to follow the changes. Additionally, include in the PR description the problem you are trying to solve, and the solution.

Problem/Requirement

Include a description of the problem or requirement to solve

Solution

Description of the solution

Refactoring

The next refactors will require a full regression testing by your QA, be very careful about when to do these changes.

  • Separate UI logic from application logic. Move logic outside of the Views. Nowadays we have MVP, MVVM, MVI, but all of them have the same intent Separation of Concerns. Try to keep the view classes lean to avoid life-cycle related problems.
  • Life Cycle Aware components. Move logic triggered by lifecycle events out of the activity/fragment. This will help you to keep your code more organized and maintainable.
  • Use LiveData and Flow to notify data changes to the View.
  • Use Coroutines to simplify your background operation handling.
  • Move data access logic to repositories.
  • Extract code to new classes using kotlin. Kotlin will help to simplify and made the code safer with java support.
  • Use DI. Encapsulate related behavior and expose it using interfaces. This will help you with the tests.

Architecture Components and Guide to App architecture

Android already has a guide with the best practices and recommended architecture to help you design robust, testable, and maintainable apps. You don’t need to reinvent the wheel, use the Android guide to App Architecture and Architecture Components collection library. The code works consistently across Android versions and devices so that we can focus on the related to our business domain.

Follow the Boy scout rule

We keep doing small changes to the code to improve it. The code gradually will get better and better. With this rule, we will see the team caring for the system as a whole, rather than individually caring for the parts they build.

And that’s all, I hope little by little we get rid of those alebrijes, and we don’t add more technical debt during the process :).

domingo, 4 de octubre de 2020

Are you a good Software Developer?

Are you a good Software Developer? Recently I heard this question and it really caught my attention.

How can we answered this? are we good because we do our testing? because we pass the sonar quality gates? because we finish our tasks on time? or based on production statistics like app rating, or existing bugs? 

Well, tools and reports will definitely help, but I think is also based on expectations. 

I still remember when I heard someone having big expectations from an specific developer. Was he able to fulfill them? Not sure.  

I think the same developer can have a different evaluation depending on whom you are asking. the client, the PO`s, the manager, the architect. 

The true is, We can not ignore those expectations. So let's focus on some of the most common expectations for a Software Developer in the job market. At the end the companies are looking for good Software Developers right? Do we really know what we are signing for?

Problem Solver and analytical skills

Here, We can have technical, and not technical problems. It refers on how we overcome the problems, on how we response to different situations.

So, we get a problem, we set a plan, we execute that plan, and finally we evaluate the results.


But wait, Is the problem even solvable? Did we find the root cause? Is the solution solving the actual need? Did we check the whole impact of the solution? Did we include all the involved parties?


Communication Skills


This very important because we are supposed to work in a team. We also need to stand up to our ideas, suggestions. We need to also interact with not technical people without jargon. If we want to succeed, Is not enough being brilliant, we need to clearly communicate our ideas.


Passion


Sometimes doing software development can be quite stressful. Long meetings, constant changes with rigid deadlines, dependencies with multiple teams with a different commitment to the project, or pressure when critical production defects are found.


And depending on the company you work for is highly possible you don't have a social life.


All of these can be enough to quit being a Software Developer, but If you haven't let's answer these questions: Do you feel satisfied doing this or would you rather being doing something else? Are you proud of your work? Do you stick to only doing your work? Do you feel motivated to keep learning new technology? If you don't have passion is ok, as long as you keep giving results.


Do you go with the best possible solution?


I want to clarify that not everything is bad about being a Software Developer, there are a lot of cool things about it, but we can have those cool things for some other discussion.


Continuous learning


Willingness to keep learning new skills, new technology, new programming languages.


Includes being aware of the latest Software development practices


Learning can come from multiple sources like:

  • Books, Blogs.
  • Individual courses.
  • Coding boot camps. Some of them provide a mentor for some months. They will guide you to speed up your learning in the selected technology.
  • Codelabs. I really like Android Codelabs.
  • Joining software open projects.
  • Find a mentor. 
  • Conferences, Meetups.
  • 1 on 1 with your manager. I have found this very useful. 


Team player


Is impossible to work alone these days. We are in constant collaboration, and We need to work on the relationships with the other team members.


I have seen amazing engineers not able to succeed in a company because they were unable to integrate with other teams. But that was also as result of lack of communication skills.


Being a good team player means helping to create a collaborative and positive working environment.


Don't being arrogant because you are the most senior developer. It means being humble. We always learn something from each other. We are all responsible for the project(s).


When the team succeed we celebrate, when the team finds some problem, we solve it together.


Are you helping others to succeed? Do you get satisfaction when the teams improved?


Are the team members happily coming to you when they have a question?



Shared knowledge


Mentoring other developers is a very important task in a project. Additionally, when you try to explain something, you know if you really understand the concept.


Are you Collaborating with ideas to improve the code, or the existing processes?


Are you engaged with software communities?


Do you share your knowledge writing Blogs? through code reviews?


Are you teaching by example?



Time/Task management. Achieve results


Can you do multitasking? Are you able to prioritize and work on the most important at the moment?

How accurate are yous estimations?

Can you manage details and keep sight of multiple projects?

Adapt to changes in requirements, and exploring new solutions.

Are you delivering quality results? are they on time?


These expectations will give us an idea of some of the most common expectations for a Software Developer in the market. But what about yourself, how do you feel? what is your personal feedback? are you a good Software Developer?


Having said that, I think I'm a good developer, but I'm not completely satisfied with what I have been doing, I still have a lot of things to improve. :)





jueves, 20 de agosto de 2020

How I lost 10x in crypto and lessons learned

and the quarantaine began... 

As a software engineer, I was very lucky to be able to work from home.what could possibly go wrong

Being at home, I started cooking, exercising, watching netflix, crunchyroll, amazon video, ohh boy, after two weeks - 24 hours alone, everything became like a routine, very boring, unhealthy, I needed to find something interesting to focus my mental energy. 

What?, Bitcoin, Blockchain, decentralized money, I was getting very excited, all of this sound incredibly amazing; so I started investing my energy in crypto. 

The first time I heard about bitcoin was in 2017,  but by then I was more interested to buying cows than anything else :)

I got some ethereum, bitcoin, chainlink, and by the end of April I was getting very good investment returns. So what went wrong? 

This is what I did wrong, yeah is all my fault and everything started with a Scam. 

I subscribed to a youtube channel posting content about a famous businessman and book author. I want to clarify here, "it was not the official channel of the businessman". My big mistake. 

By May 10, we had all the excitement about bitcoin halving. I still remember seeing in the channel the bitcoin giveaway. How it was supposed to work? you send some bitcoin and you get double amount back to the same address. I checked the site, and the transactions, everything look pretty real. I got very emotional, and yeah I sent some of my bitcoin to that address. 😅

I lost my crypto in a Scam, and the next days I was feeling very silly, stupid, how can I think people will love me so much to give me free money, hahaha. 

The next days, I was thinking, Isn't there some place were I can report all of this cyber crimes? 
After some research, I found a couple of options, but there is a company tracking the scams, so I created a request to investigate the scam I was victim of.

When creating the ticket I had to provide information like my email, phone, and the address where I sent the crypto in the scam. Everything was feeling like general information they will need to do the investigation. 

well, maybe it was a coincidence, but 15 minutes later after creating that ticket, my account was accessed and all my crypto was stolen from my account in a very popular exchange.

How did the hackers got access? I felt like my password was strong enough, I had 2 factor authentication enabled, my Account seed was stored only in paper, and still someone enter to my account, converted all my crypto to bitcoin, and sent to an address. 

I contacted the exchange, with the hope they can return my stolen bitcoin, but after some days, they replied back saying that all the operations were executed using one of my registered devices. 

In some way the hacker got access to my computer, and also got access to my phone authentication code. 

These are the suggestions I got from the exchange:
  • Scan the devices with anti virus.
  • Reset email password. 
  • Check unfamiliar rules, filters, forwarding addresses, recovery emails.
  • Reset password in the exchange.
  • Contact mobile service provider to inquire about security measures to prevent unauthorized changes such as SIM swap or phone port.
Because it was my fault, the exchange didn't do anything, but they offer help providing transactions details for local authorities. I sent another ticket to the FBI - Internet Crime Complain Center but I never got any replied back.

I was feeling down for a couple of days, the hacker stole the saving I got with a lot of hard work, but after some time I decided to keep learning and investing in crypto, I think is a really good opportunity, but we definitely have some risks to be aware of.

These are the lessons I learned. I hope they help new people learning crypto, so they don't make the same mistakes.
  1. Don't keep your crypto online all the time (hot wallet), get your hardware wallet. I personally got my Ledger and now I feel safer.
  2. Don't save passwords in chrome. If they get access to your computer, now they have access to all your online accounts.
  3. Don't share too much personal information online. We share a lot of information online, specially in social networks. For the sim swap, hacker will need your personal information. 
  4. If you want to keep crypto online, don't keep all your crypto in a single account. 
  5. Be careful when picking the sources to learn about crypto. Now I follow better sources of information, and mostly only official twitter accounts, and youtube channels. I highly recommend: 
    1. Digital Asset News. The channels I was following before never mentioned the scams going on. This channel is fighting the scams every day. Now every time I see a Scam I also report to google. 
    2. Ivan on tech
    3. BitBoy Crypto.
    4. Coin Bureau.
    5. Chico Crypto.
    6. Altcoin Daily.







martes, 5 de enero de 2016

Continuous Integration - Solving Android Dependencies in Offline Mode

Are you using Jenkins server without access to internet for security reasons?

If you answer yes, then maybe you have experienced getting a compilation failure just because Jenkins is unable to find some dependencies.

Well one way to solve this problem is to put all the dependencies for the project in the libs directory.

But how do I know what are the jars, aars I need to include in the libs directory?

Umm, Gradle and maven have already define the way to solve dependencies, and transitive dependencies.

If you run the following command

gradle :app:dependencies

You will get a list with all the dependencies and transitive dependencies for the project. Then, Do I need to include all that dependencies one by one?, looking for them on Maven Central Repository, downloading the jar file and then copying into the libs folder. So much work, right.

Well, We can ask maven to help us with this task.

Step by step

  1. Install maven
  2. Add maven to the path
  3. Create a pom file with the following content:
  4. 
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
    http://maven.apache.org/maven-v4_0_0.xsd">
    
        <modelVersion>4.0.0</modelVersion>
        <groupId>mx.com.project</groupId>
        <artifactId>ProjectDependencies</artifactId>
        <version>1.0</version>
        <packaging>pom</packaging>
        <description>Project dependencies.</description>
    
        <repositories>
            <repository>
                <id>maven2</id>
                <name>Maven2</name>
                <url>http://repo1.maven.org/maven2/</url>
            </repository>
    
            <repository>
                <id>android-support</id>
                <url>file://${env.ANDROID_HOME}/extras/android/m2repository</url>
            </repository>
        </repositories>
    
        <dependencies>
    
            <!-- aar dependencies are coming from the repository ANDROID_HOME/extras/android/m2repository -->
            <dependency>
                <groupId>com.android.support</groupId>
                <artifactId>appcompat-v7</artifactId>
                <version>23.1.1</version>
                <type>aar</type>
            </dependency>
    
            <dependency>
                <groupId>com.android.support</groupId>
                <artifactId>design</artifactId>
                <version>23.1.1</version>
                <type>aar</type>
            </dependency>
    
            <dependency>
                <groupId>com.android.support</groupId>
                <artifactId>multidex</artifactId>
                <version>1.0.1</version>
                <type>aar</type>
            </dependency>
            
            <!-- jar dependencies are coming from maven central repository -->
    
            <dependency>
                <groupId>com.dubsmash.volley</groupId>
                <artifactId>library</artifactId>
                <version>1.0.20</version>
            </dependency>
    
            <dependency>
                <groupId>com.google.code.gson</groupId>
                <artifactId>gson</artifactId>
                <version>2.5</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>3.4</version>
            </dependency>
    
            <dependency>
                <groupId>de.greenrobot</groupId>
                <artifactId>eventbus</artifactId>
                <version>2.4.0</version>
            </dependency>
    
            <dependency>
                <groupId>com.google.dagger</groupId>
                <artifactId>dagger</artifactId>
                <version>2.0</version>
            </dependency>
    
        </dependencies>
    </project>
    
    

    Note the registration of a repository pointing to my file system where I have downloaded the android support repository. If you haven't installed the Android Support Library, open the SDK Manager and install it before executing the maven command.

  5. Get the dependencies and transitive dependencies. execute the following command:
  6. mvn dependency:copy-dependencies -DoutputDirectory=/tmp/temporalDirectory/ -U
    
  7. Copy the .jar and .aar files from the /tmp/temporalDirectory/ into the libs directory
  8. Register flat repository pointing to the libs directory
  9. repositories {
        ...
        flatDir {
            dirs 'libs'
        }
    }
    
  10. Register jar dependencies and aar dependencies
  11. dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
    
        compile(name: 'appcompat-v7-23.1.1', ext: 'aar')
        compile(name: 'design-23.1.1', ext: 'aar')
        compile(name: 'multidex-1.0.1', ext: 'aar')
        compile(name: 'recyclerview-v7-23.1.1', ext: 'aar')
        compile(name: 'support-v4-23.1.1', ext: 'aar')
    
  12. Create and install your apk

I was having a hard time trying to solve the dependencies for my project, I hope you don't have the same problem using this info as reference.

lunes, 30 de noviembre de 2015

Android Software Developer Interview Questions

Android Interview Questions

Do you want to apply for a Job as an Android Developer?, well this time I shared the most popular questions I got while I was in marketing. I hope they are helpful for you.

If I can help with something, just send me an email and I will be happy to help.

Android Framework

  • Describe the architecture of Android Operating System
  • Difference between fragment and activity
  • What is an sticky broadcast receiver
  • Elements of an Intent
  • Different types of services
  • What is ANR and how to avoid it
  • Define Async Task
  • Can you run Async Task in parallel
  • Different types of components from Android Framework
  • What is a nine patch image
  • How do you disable execution of a service from outside of the application
  • What types of Context exist in Android
  • What is a memory leak?
  • What type of context do you pass when you are creating a new view
  • Difference between IntentService and Service
  • How do you communicate multiple threads in Android
  • How many .dex files can you have in an android application
  • What is DDMS, what do you use it for?
  • What are the essential items in an Android Project?
  • What is a weak reference?
  • Explain the life cycle of an activity
  • Difference between Activity and fragment?
  • What is Dalvik Virtual Machine?
  • What is ART?
  • What is ADB?
  • What is a .dex file?
  • Tell me about the best practices you know to program in Android
  • What are the use of DDMS?
  • How do you create Unit Testing in Android?
  • How do you use a AlarmManager?
  • How do you configure an alarm manager to fire every day at a specific time of the day?
  • What is a ViewHolder?
  • What happen if I define two activities with an intent filter with the category of launcher?

Core Java

  • What are the ways to create a Thread?
  • What is a dead lock
  • What is multi inheritance?, is allow in java?
  • What is final, finalize()
  • Define Static
  • What is an abstract class?
  • What is generics
  • What is polymorphism
  • What is encapsulation

Design Patterns

  • What is Singleton Design Pattern
  • What is Thread Safe Singleton Design Pattern
  • What is Abstract Factory Design Pattern
  • What is Strategy Design Pattern
  • Tell me some design patterns that you have applied in Android

Web Services

  • Difference between REST and SOAP
  • How do you decide between REST and SOAP?
  • Algorithms

    • How do you remove duplicated elements in an array of ints
    • How to get the middle element of an Simple Linked List in one pass
    • How to know if a strings are palindromes
    • How to determine if two strings are anagrams
    • How do you get the common parent of two given nodes? Every node has a reference for its parents, and the root node has a reference to null.
    • 
                 A
      
                / \ \
      
               B   C  M
      
              /     \
      
             D       E
      
            / \
      
           F   G
      
                \
      
                 H
      
      

    jueves, 19 de noviembre de 2015

    Common commands for Android development

    Hi my friends, this time i will share the most common commands I use on a daily basis working as an Android Developer. If you want to add some more commands feel free to comment and we can extend this list.

    Android

    Update android sdk in silent mode

    • Mac
    • ./android update sdk --no-ui

    List available packages for installation

    • Mac
    • ./android list sdk

    Android Debug Bridge (ADB)

    Execute commands on device.

    • Install application (apk)
    • adb install /pathToApk
    • Replace existing application installation (apk)
    • adb install -r /pathToApk
    • Start main activity (apk)
    • adb shell am start -a android.intent.action.MAIN -n applicationPackage/.MainActivity
    • List applications installed by package name
    • adb shell pm list packages
    • Uninstall application by package name
    • adb shell pm uninstall mx.com.app
    • List files on sdcard
    • adb shell ls sdcard/
    • List files on sdcard
    • adb shell ls sdcard/
    • Get a file from device sdcard
    • adb pull /sdcard/directory/file.extension
    • Send a file to the device sdcard
    • adb push /pathToFile/file.extension /sdcard/directory/
    • Run adb as root on device. This allow to install an aplicacion as preinstalled in the device.
    • adb root
    • Mount file system with read-write permissions
    • adb remount

    Gradle

    • Show graph of dependencies for the project
    • gradle :app:dependencies
    • Show available tasks
    • gradle tasks
    • Package application
    • gradle assembleDebug
    • Test application
    • gradle assembleDebug
    • Refresh dependencies
    • gradle --refresh-dependencies
    • Offline mode
    • gradle assembleDebug -offline
    • Debug mode
    • gradle assembleDebug -debug

    martes, 10 de noviembre de 2015

    Interact across user Android profiles

    It has been a while since the last time I shared something. Well, this time i will write about how to communicate between user profiles in Android because as we already know in latest releases we have the option to create multiple user profiles in one device. And because i have some trouble trying to figure out how to do it :).

    First i want to share the link with the document where you can find more info related to building applications with multi users profiles.

    But lets start with some requirements to create the test application:

    • Android device with user profiles functionality
    • Rooted device
    • System application permissions.

    Register for the switch user event

    Add the following code to register as a listener of the user profile change event

    @Override
        protected void onCreate(Bundle savedInstanceState) {
            ...
    
            SwitchingUserReceiver receiver = new SwitchingUserReceiver();
            IntentFilter switchingUserProfileEvent = new IntentFilter();
            switchingUserProfileEvent.addAction(Intent.ACTION_USER_BACKGROUND);
            switchingUserProfileEvent.addAction(Intent.ACTION_USER_FOREGROUND);
            registerReceiver(receiver, switchingUserProfileEvent);
        }
    

    Create broadcast receiver for the switch user event

    Create the following broadcast receiver to listen for the switching user profile event.

    public class SwitchingUserReceiver extends BroadcastReceiver {
    
        private static final String TAG = SwitchingUserReceiver.class.getSimpleName();
    
        @Override
        public void onReceive(Context context, Intent intent) {
        }
    }
    

    Because we register the broadcast receiver in runtime, is not necessary to add this event in the Manifest file.

    Launch broadcast receiver to interact with an application in the starting user profile

    UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
                final int userId = UserHelper.getCurrentUser();
    int previousUser = intent.getExtras().getInt("android.intent.extra.user_handle");
    
                UserHandle userHandle = userManager.getUserForSerialNumber(userId);
                Log.d(TAG, "userHandle " + userHandle);
    
                for (Method method : context.getClass().getMethods()) {
                    if ("sendBroadcastAsUser".equalsIgnoreCase(method.getName())) {
                        if (method.getParameterTypes().length == 2) {
                            method.setAccessible(true);
                            Intent broadcastIntent = new Intent();
                            broadcastIntent.setAction("com.example.clerks.myapplication.myaction");
                            int processId = android.os.Process.myPid();
                            broadcastIntent.putExtra("user", previousUser);
                            broadcastIntent.putExtra("processId", processId);
                            method.invoke(context, broadcastIntent, userHandle);
                        }
                    }
                }
    
    ...AndroidManifest...
    <uses-permission android:name="android.permission.MANAGE_USERS" />
        <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"
                         android:protectionLevel="signatureOrSystem"/>
    

    Now we are going to use the method sendBroadcastAsUser. This method is not available to execute directly, but we are going to invoke it by reflection.

    sendBroadcastAsUser receives as firs parameter the intent with the action to send the broadcast and the user where we want to send the brodcast. Note that when this onReceive method executes, the current user has already change, so the user in the foreground is the user profile that we select in the user profile interface. Thats why we are sending the broadcast to this current user (userHandle).

    And the action("com.example.clerks.myapplication.myaction"), is the one that we are going to use to select our broadcast receiver.

    To execute this code we require the permissions to MANAGE_USERS and INTERACT_ACROSS_USERS, so we are going to create system application.

    Broadcast receiver for the custom action

    public class OnUserSwitchedReceiver extends BroadcastReceiver {
    
        private static final String TAG = OnUserSwitchedReceiver.class.getSimpleName();
    
        @Override
        public void onReceive(final Context context, Intent intent) {
            final int previousUser = intent.getIntExtra("user", -1);
            final int previousProcessId = intent.getIntExtra("processId", -1);
            final int processId = android.os.Process.myPid();
    
            final int userId = UserHelper.getCurrentUser();
            Log.d(TAG, "Active user = " + userId);
    
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(context, String.format("Message received. Process Ids: %d vs %d, Users: %d vs %d",
                                    processId, previousProcessId, userId,
                                    previousUser),
                            Toast.LENGTH_LONG).show();
                }
            });
        }
    }
    
    <receiver android:name=".OnUserSwitchedReceiver">
                <intent-filter>
                    <action android:name="com.example.clerks.myapplication.myaction" />
                </intent-filter>
            </receiver>
    

    In this case we have to register this broadcast receiver in the manifest file for the application that can handle this action

    Helper class to get the current user

    public class UserHelper {
        public static int getCurrentUser() {
            Method getCurrentUser = null;
            try {
                getCurrentUser = ActivityManager.class.getDeclaredMethod("getCurrentUser");
                getCurrentUser.setAccessible(true);
                return (int) getCurrentUser.invoke(null);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return -1;
        }
    }
    

    Deploy application

    echo "setting as root"
    adb root
    
    echo "remounting device"
    adb remount
    
    echo "creating package for application"
    gradle clean assembleDebug
    mv build/outputs/apk/app-debug.apk build/outputs/apk/MultiprofileApp.apk
    
    echo "removing current apk in priv-app"
    adb shell rm system/priv-app/MultiprofileApp/MultiprofileApp.apk
    
    echo "moving current apk to priv-app"
    adb push build/outputs/apk/MultiprofileApp.apk system/priv-app/MultiprofileApp/ 
    
    echo "Changing permissions to directory MultiprofileApp"
    adb shell chmod -R 755 system/priv-app/MultiprofileApp
    
    echo "changing permissions to apk (644)"
    adb shell chmod 644 system/priv-app/MultiprofileApp/MultiprofileApp.apk
    
    echo "restarting device"
    adb reboot
    

    As you can see I have created a directory call MultiprofileApp in the priv-app directory. priv-app is used to install sytem applications. After create the directory and push the apk file, we need to reboot the device so the operating system can scan again the applications.

    Test application

    Start application, change the user and check that the toast appears in the open user.

    Some things to keep in mind

    • The context has another methods to interact between users, for example, start a service and an activity, I just test the startServiceAsUser and sendBroadcastAsUser but with startServiceAsUser I was getting all the time an exception related to INTERACT_ACROSS_USERS permission, even if i have include that permission and install my application as preinstalled, i was getting that exception. But you can try by yourself.
    • I´m having some problems to get the method sendBroadcastAsUser to execute in the current Context, that's why you can see that for approach.

    And that's all, now you can interact between system applications.