Categories
discuss

compare JS objects with values null and empty string

How can I compare these below two JavaScript objects to be equal and true

var obj1 = {
  'a': 'something',
  'b': null
};
var obj2 = {
  'a': 'something',
  'b': ''
}

var isTrue = _.isEqual(obj1, obj2);

alert(isTrue);
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>

Answer

In theory, they are not equals. '' !== null.
What you could do, is change every empty value to be null first, an then compare them.

var obj1 = {
  'a': 'something',
  'b': null
};
var obj2 = {
  'a': 'something',
  'b': ''
}



var isTrue = _.isEqual(mapEmptyValueToNull(obj1), mapEmptyValueToNull(obj2));
console.log(isTrue);

// we change every value of '' to null.
function mapEmptyValueToNull(object) {
  Object.keys(object).forEach((key) => {
    if(object[key] === '') {
      object[key] = null;
    }
  });
  return object;
}
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>
Categories
discuss

Kotlin – What does companion object fun do?

Declaring a “static” function in Kotlin is done using:

companion object {
    fun classFoo() {
        //do something
    }
}

However I was mistakenly coding

companion object fun classFoo() {
     //do something
}

Expecting the code to do the same, if only one static function was required.

The compiler doesn’t argue about that, and it seems to be valid as the compiler expects a fun name and parameters. But I never found how to call that function from other class.

What does that form of companion object fun do? there is no doc available about that.

Answer

class Test {
    companion object fun classFoo() {
        //do something
    }
}

is equivalent to

class Test {
    companion object // Add "{ }" to make it explicit that the object body is empty

    fun classFoo() {
        //do something
    }
}

i.e. a class with an empty companion object (which is valid syntax) and a normal member function, callable in the usual way:

Test().classFoo()
Categories
discuss

Push notifications with no sound on MIUI

My app’s main functionality is push-notification messages sent from remote server. I am using FCM as a message delivery service. My problem is that notifications come without any sound on Xiaomi Mi 9 Lite (Android 9/MIUI 11). However, on Xiaomi Redmi Note 5 (Android 9/MIUI 10) sound works fine and on Samsung Galaxy S7 Edge (Android 8) as well. I created MessagingService which extends FirebaseMessagingService and notification channel as written in documentation.

Here is my code:

public class MessagingService extends FirebaseMessagingService {

    private static String channelId;
    private NotificationManager notificationManager;
    private NotificationChannel notificationChannel;
    private NotificationCompat.Builder notificationBuilder;

    private MessagesViewModel viewModel;

    public MessagingService() { }

    @Override
    public void onCreate() {
        super.onCreate();
        channelId = getResources().getString(R.string.default_notification_channel_id);
        notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

        final Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

        notificationBuilder = new NotificationCompat.Builder(this, channelId);
        notificationBuilder.setSmallIcon(R.raw.metrial_message_icon);
        notificationBuilder.setAutoCancel(false);
        notificationBuilder.setSound(soundUri);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            final AudioAttributes audioAttributes = new AudioAttributes.Builder()
                    .setUsage(AudioAttributes.USAGE_NOTIFICATION)
                    .build();

            String name = getString(R.string.channel_name);
            String description = getString(R.string.channel_description);
            int importance = NotificationManager.IMPORTANCE_HIGH;
            notificationChannel = new NotificationChannel(channelId, name, importance);
            notificationChannel.setDescription(description);
            notificationChannel.enableLights(true);
            notificationChannel.setShowBadge(true);
            notificationChannel.setSound(soundUri, audioAttributes);
            notificationManager.createNotificationChannel(notificationChannel);
            notificationBuilder.setChannelId(channelId);
        }
        else {
            notificationBuilder.setPriority(NotificationCompat.PRIORITY_HIGH);
            notificationBuilder.setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL);
            notificationBuilder.setLights(Color.WHITE, 500, 5000);
        }

        viewModel = new MessagesViewModel(getApplication());
    }

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

    @Override
    public void onNewToken(@NonNull String s) {
        super.onNewToken(s);
        logger.info("onNewToken()");
        ConnectionParameters.getInstance().setToken(s);
        MyPrefs.getInstance(getApplicationContext()).putString(Constants.TOKEN, s);
    }

    @Override
    public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);

        final String messageId = remoteMessage.getData().get("message_id");
        final String title = remoteMessage.getData().get("title");
        final String body = remoteMessage.getData().get("body");

        if (messageId != null && title != null && body != null) {

            final Message message = new Message();
            message.setMessageId(messageId);
            message.setTitle(title);
            message.setContent(body);
            message.setTimestamp(new Date());

            try {
                message.setNotificationId((int)viewModel.insert(message));
            } catch (ExecutionException | InterruptedException e) {
                e.printStackTrace();
            }

            logger.info("onMessageReceived(): notificationId=" + message);

            if (MyPrefs.getInstance(getApplicationContext()).getBoolean(Constants.ENABLE_PUSH)) {
                notificationBuilder.setContentTitle(title);
                notificationBuilder.setContentText(body);

                final Intent notifyIntent = new Intent(this, MessageInfoActivity.class);
                notifyIntent.putExtra(Constants.ARG_MESSAGE_OBJECT, message);
                TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
                stackBuilder.addNextIntentWithParentStack(notifyIntent);
                PendingIntent pendingActivityIntent =
                        stackBuilder.getPendingIntent(message.getNotificationId(), PendingIntent.FLAG_UPDATE_CURRENT);
                notificationBuilder.setContentIntent(pendingActivityIntent);

                final Notification notification = notificationBuilder.build();
                notification.defaults = Notification.DEFAULT_SOUND|Notification.DEFAULT_LIGHTS;
                notificationManager.notify(message.getNotificationId(), notification);
            }
        }
    }

    private final Logger logger = LoggerFactory.getLogger(getClass());
}

And in Settings->Notifications I got the following parameters: enter image description here

And inside my push-notifications-channel sound is enabled but whenever a message comes, it seems like app notification settings override parameters in notification channel. enter image description here

There should be some solution because in popular apps such WhatsApp, Telegram, etc., these switches are enabled after installation (by default). Hope, someone helps!

Answer

As nobody provided better solution, I guess there is no way to allow sound/badge counter/floating notifications programmatically on MIUI (and mostly on other Chinese OEMs). It is a user’s privilege to turn these settings on manually. Therefore, to enhance UX, it is important to decrease the quantity of “clicks” as much as possible. So, we could provide a dialog describing how to enable the features above with button leading to App’s settings. Namely, to open a notification settings page through Intent, do the following:

final Intent notificationSettingsIntent = new Intent();
notificationSettingsIntent
        .setAction("android.settings.APP_NOTIFICATION_SETTINGS");
notificationSettingsIntent
        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    notificationSettingsIntent.putExtra(
            "android.provider.extra.APP_PACKAGE",
            activity.getPackageName());
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        notificationSettingsIntent.putExtra(
                "app_package",
                activity.getPackageName());
        notificationSettingsIntent.putExtra(
                "app_uid", 
                activity.getApplicationInfo().uid);
}
activity.startActivityForResult(
        notificationSettingsIntent, 
        NOTIFICATIONS_SETTINGS_REQUEST_CODE);

and you could open a dialog with button “Open notification settings” clicking on which triggers the code snippet above.

Categories
discuss

Sending API requests from MusicBrowserServiceCompat in Android Auto

I am trying to build a music app like Spotify. I am having difficulties in integrating the app with Android Auto. I have a background service extended from MediaBrowserServiceCompat that plays music. In Android auto mode, when and from where I send a request to the remote server to get playlists and songs?

I checked the Google’s Universal Player codes, I couldn’t understand how they are getting the songs (and it was in Kotlin… the codes were too short to understand)
https://github.com/android/uamp

I also found MediaBrowserCompat that has something to do with connections, however I am not sure whether it is a API connection or a Service.

How do I do it? How do we send requests to a remote server, get results, and populate them?

Answer

So just to clarify your question, you are trying to replicate Google’s Universal Player codes which can be found https://github.com/android/uamp, but in java and you aren’t sure where they are calling the API/getting the songs themselves?

It appears that they are creating a ConnectionService in AutomotiveMusicService.kt and from that they are calling the API in the common section.

I think this music demo might also help as I believe it is accomplishing the same thing.

Categories
discuss

Cancel coroutines in a BroadcastReceiver

I was wondering how to deal with coroutines cancelation in a BroadcastReceiver. I have to run some suspending methods and for the moment I am using a GlobalScope.launch or a runBlocking. Is there another way in order to control the job that is being fired and cancel when the BroadcastReceiver() is finished? It’s an AlarmManager specifically.

For all saying to switch to a WorkManager the answer is no because I’m scheduling work at exact time and WorkManager doesn’t do that for you. So in order to set Alarms I have to read some data from a suspend method once the AlarmManager is fired. I also tried this solution:

//inside Alarm Managers onReceive Method

val job = coroutineScope.launch {
    delayingOperationMethod()
}

job.invokeOnCompletion {
    coroutineScope.cancel()
}

Where job is just:

private val job: Job = Job()
private val coroutineScope = CoroutineScope(job + Dispatchers.IO)

Is this a way of doing it?

Answer

Looks like the GlobalScope was the best solution:

GlobalScope.launch(Dispatchers.IO){
 ///
}
Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..