Skip to content

Commit

Permalink
Send out PROVIDER_CHANGED broadcasts again, fixes #822 (#825)
Browse files Browse the repository at this point in the history
Since Android 8 it's not possible to listen to implicit broadcasts anymore when the reciever is declared in the AndroidManifest.xml.
In a previous commit we disabled sending out broadcasts to other apps. This caused some trouble.
For new we hard code 3rd party receiver package names in a resource array. This is supposed to be changed later on, see #824.
  • Loading branch information
dmfs authored Aug 17, 2019
1 parent e711e6e commit 1dcd943
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 11 deletions.
2 changes: 1 addition & 1 deletion dependencies.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
def jems_version = '1.23'
def jems_version = '1.24'
def contentpal_version = '0.5'
def androidx_test_runner_version = '1.1.1'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1317,15 +1317,8 @@ protected void onEndTransaction(boolean callerIsSyncAdapter)
super.onEndTransaction(callerIsSyncAdapter);
if (mChanged.compareAndSet(true, false))
{
Intent providerChangedIntent = new Intent(Intent.ACTION_PROVIDER_CHANGED, TaskContract.getContentUri(mAuthority));
updateNotifications();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
// for now we only notify our own package
// we'll have to figure out how to do this correctly on Android 8+, e.g. how is it done by CalendarProvider and ContactsProvider
providerChangedIntent.setPackage(getContext().getPackageName());
}
getContext().sendBroadcast(providerChangedIntent);
Utils.sendActionProviderChangedBroadCast(getContext(), mAuthority);
}

if (Boolean.TRUE.equals(mStaleListCreated.get()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,21 @@
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import org.dmfs.iterables.SingletonIterable;
import org.dmfs.jems.iterable.composite.Joined;
import org.dmfs.jems.iterable.decorators.Mapped;
import org.dmfs.jems.procedure.composite.Batch;
import org.dmfs.provider.tasks.TaskDatabaseHelper.Tables;
import org.dmfs.provider.tasks.utils.ResourceArray;
import org.dmfs.provider.tasks.utils.With;
import org.dmfs.tasks.contract.TaskContract;
import org.dmfs.tasks.contract.TaskContract.Instances;
import org.dmfs.tasks.contract.TaskContract.SyncState;
import org.dmfs.tasks.contract.TaskContract.TaskListColumns;
import org.dmfs.tasks.contract.TaskContract.TaskListSyncColumns;
import org.dmfs.tasks.contract.TaskContract.TaskLists;
import org.dmfs.tasks.contract.TaskContract.Tasks;
import org.dmfs.tasks.provider.R;

import java.util.ArrayList;
import java.util.Arrays;
Expand All @@ -49,8 +56,18 @@ public static void sendActionProviderChangedBroadCast(Context context, String au
{
// TODO: Using the TaskContract content uri results in a "Unknown URI content" error message. Using the Tasks content uri instead will break the
// broadcast receiver. We have to find away around this
Intent providerChangedIntent = new Intent(Intent.ACTION_PROVIDER_CHANGED, TaskContract.getContentUri(authority));
context.sendBroadcast(providerChangedIntent);
// TODO: coalesce fast consecutive broadcasts, a delay of up to 1 second should be acceptable

new With<>(new Intent(Intent.ACTION_PROVIDER_CHANGED, TaskContract.getContentUri(authority)))
.process(providerChangedIntent ->
new Batch<Intent>(context::sendBroadcast)
.process(new Mapped<>(
packageName -> new Intent(providerChangedIntent).setPackage(packageName),
// TODO: fow now we hard code 3rd party package names, this should be replaced by some sort or registry
// see https://github.com/dmfs/opentasks/issues/824
new Joined<>(
new SingletonIterable<>(context.getPackageName()),
new ResourceArray(context, R.array.opentasks_provider_changed_receivers)))));
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2019 dmfs GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.dmfs.provider.tasks.utils;

import android.content.Context;

import org.dmfs.iterators.elementary.Seq;

import java.util.Iterator;


/**
* An {@link Iterable} of a string array resource.
*
* @author Marten Gajda
*/
public final class ResourceArray implements Iterable<String>
{
private final Context mContext;
private final int mResource;


public ResourceArray(Context context, int resource)
{
mContext = context;
mResource = resource;
}


@Override
public Iterator<String> iterator()
{
return new Seq<>(mContext.getResources().getStringArray(mResource));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2019 dmfs GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.dmfs.provider.tasks.utils;

import org.dmfs.jems.procedure.Procedure;
import org.dmfs.jems.single.Single;


/**
* Experiemental Procedure which calls another procedure with a given value.
* <p>
* TODO move to jems if this works out well
*
* @author Marten Gajda
*/
@Deprecated
public final class With<T> implements Procedure<Procedure<T>>
{
private final Single<T> mValue;


public With(T value)
{
this(() -> value);
}


public With(Single<T> value)
{
mValue = value;
}


@Override
public void process(Procedure<T> delegate)
{
delegate.process(mValue.value());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="opentasks_provider_changed_receivers">
<item>org.andstatus.todoagenda</item>
</string-array>
</resources>

0 comments on commit 1dcd943

Please sign in to comment.