Skip to content

Parcelable object #625

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 19, 2017
84 changes: 78 additions & 6 deletions Parse/src/main/java/com/parse/ParseACL.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
*/
package com.parse;

import android.os.Parcel;
import android.os.Parcelable;

import org.json.JSONException;
import org.json.JSONObject;

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
* A {@code ParseACL} is used to control which users can access or modify a particular object. Each
Expand All @@ -22,7 +26,7 @@
* permissions to "the public" so that, for example, any user could read a particular object but
* only a particular set of users could write to that object.
*/
public class ParseACL {
public class ParseACL implements Parcelable {
private static final String PUBLIC_KEY = "*";
private final static String UNRESOLVED_KEY = "*unresolved";
private static final String KEY_ROLE_PREFIX = "role:";
Expand Down Expand Up @@ -61,6 +65,11 @@ private static class Permissions {
return json;
}

/* package */ void toParcel(Parcel parcel) {
parcel.writeByte(readPermission ? (byte) 1 : 0);
parcel.writeByte(writePermission ? (byte) 1 : 0);
}

/* package */ boolean getReadPermission() {
return readPermission;
}
Expand All @@ -74,6 +83,10 @@ private static class Permissions {
boolean write = object.optBoolean(WRITE_PERMISSION, false);
return new Permissions(read, write);
}

/* package */ static Permissions createPermissionsFromParcel(Parcel parcel) {
return new Permissions(parcel.readByte() == 1, parcel.readByte() == 1);
}
}

private static ParseDefaultACLController getDefaultACLController() {
Expand Down Expand Up @@ -205,7 +218,7 @@ public ParseACL(ParseUser owner) {
}

/* package for tests */ void resolveUser(ParseUser user) {
if (user != unresolvedUser) {
if (!isUnresolvedUser(user)) {
return;
}
if (permissionsById.containsKey(UNRESOLVED_KEY)) {
Expand Down Expand Up @@ -336,20 +349,27 @@ private void setUnresolvedWriteAccess(ParseUser user, boolean allowed) {
private void prepareUnresolvedUser(ParseUser user) {
// Registers a listener for the user so that when it is saved, the
// unresolved ACL will be resolved.
if (this.unresolvedUser != user) {
if (!isUnresolvedUser(user)) {
permissionsById.remove(UNRESOLVED_KEY);
unresolvedUser = user;
user.registerSaveListener(new UserResolutionListener(this));
unresolvedUser.registerSaveListener(new UserResolutionListener(this));
}
}

private boolean isUnresolvedUser(ParseUser other) {
// This might be a different instance, but if they have the same local id, assume it's correct.
if (other == null || unresolvedUser == null) return false;
return other == unresolvedUser || (other.getObjectId() == null &&
other.getOrCreateLocalId().equals(unresolvedUser.getOrCreateLocalId()));
}

/**
* Get whether the given user id is *explicitly* allowed to read this object. Even if this returns
* {@code false}, the user may still be able to access it if getPublicReadAccess returns
* {@code true} or a role that the user belongs to has read access.
*/
public boolean getReadAccess(ParseUser user) {
if (user == unresolvedUser) {
if (isUnresolvedUser(user)) {
return getReadAccess(UNRESOLVED_KEY);
}
if (user.isLazy()) {
Expand Down Expand Up @@ -381,7 +401,7 @@ public void setWriteAccess(ParseUser user, boolean allowed) {
* {@code true} or a role that the user belongs to has write access.
*/
public boolean getWriteAccess(ParseUser user) {
if (user == unresolvedUser) {
if (isUnresolvedUser(user)) {
return getWriteAccess(UNRESOLVED_KEY);
}
if (user.isLazy()) {
Expand Down Expand Up @@ -536,4 +556,56 @@ public void done(ParseObject object, ParseException e) {
/* package for tests */ Map<String, Permissions> getPermissionsById() {
return permissionsById;
}

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
writeToParcel(dest, new ParseObjectParcelEncoder());
}

/* package */ void writeToParcel(Parcel dest, ParseParcelEncoder encoder) {
dest.writeByte(shared ? (byte) 1 : 0);
dest.writeInt(permissionsById.size());
Set<String> keys = permissionsById.keySet();
for (String key : keys) {
dest.writeString(key);
Permissions permissions = permissionsById.get(key);
permissions.toParcel(dest);
}
dest.writeByte(unresolvedUser != null ? (byte) 1 : 0);
if (unresolvedUser != null) {
// Encoder will create a local id for unresolvedUser, so we recognize it after unparcel.
encoder.encode(unresolvedUser, dest);
}
}

public final static Creator<ParseACL> CREATOR = new Creator<ParseACL>() {
@Override
public ParseACL createFromParcel(Parcel source) {
return new ParseACL(source, new ParseObjectParcelDecoder());
}

@Override
public ParseACL[] newArray(int size) {
return new ParseACL[size];
}
};

/* package */ ParseACL(Parcel source, ParseParcelDecoder decoder) {
shared = source.readByte() == 1;
int size = source.readInt();
for (int i = 0; i < size; i++) {
String key = source.readString();
Permissions permissions = Permissions.createPermissionsFromParcel(source);
permissionsById.put(key, permissions);
}
if (source.readByte() == 1) {
unresolvedUser = (ParseUser) decoder.decode(source);
unresolvedUser.registerSaveListener(new UserResolutionListener(this));
}
}
}
15 changes: 14 additions & 1 deletion Parse/src/main/java/com/parse/ParseAddOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
*/
package com.parse;

import android.os.Parcel;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
Expand All @@ -20,6 +22,8 @@
* An operation that adds a new element to an array field.
*/
/** package */ class ParseAddOperation implements ParseFieldOperation {
/* package */ final static String OP_NAME = "Add";

protected final ArrayList<Object> objects = new ArrayList<>();

public ParseAddOperation(Collection<?> coll) {
Expand All @@ -29,12 +33,21 @@ public ParseAddOperation(Collection<?> coll) {
@Override
public JSONObject encode(ParseEncoder objectEncoder) throws JSONException {
JSONObject output = new JSONObject();
output.put("__op", "Add");
output.put("__op", OP_NAME);
output.put("objects", objectEncoder.encode(objects));
return output;
}

@Override
public void encode(Parcel dest, ParseParcelEncoder parcelableEncoder) {
dest.writeString(OP_NAME);
dest.writeInt(objects.size());
for (Object object : objects) {
parcelableEncoder.encode(object, dest);
}
}

@Override
public ParseFieldOperation mergeWithPrevious(ParseFieldOperation previous) {
if (previous == null) {
return this;
Expand Down
15 changes: 14 additions & 1 deletion Parse/src/main/java/com/parse/ParseAddUniqueOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
*/
package com.parse;

import android.os.Parcel;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
Expand All @@ -22,6 +24,8 @@
* An operation that adds a new element to an array field, only if it wasn't already present.
*/
/** package */ class ParseAddUniqueOperation implements ParseFieldOperation {
/* package */ final static String OP_NAME = "AddUnique";

protected final LinkedHashSet<Object> objects = new LinkedHashSet<>();

public ParseAddUniqueOperation(Collection<?> col) {
Expand All @@ -31,12 +35,21 @@ public ParseAddUniqueOperation(Collection<?> col) {
@Override
public JSONObject encode(ParseEncoder objectEncoder) throws JSONException {
JSONObject output = new JSONObject();
output.put("__op", "AddUnique");
output.put("__op", OP_NAME);
output.put("objects", objectEncoder.encode(new ArrayList<>(objects)));
return output;
}

@Override
public void encode(Parcel dest, ParseParcelEncoder parcelableEncoder) {
dest.writeString(OP_NAME);
dest.writeInt(objects.size());
for (Object object : objects) {
parcelableEncoder.encode(object, dest);
}
}

@Override
@SuppressWarnings("unchecked")
public ParseFieldOperation mergeWithPrevious(ParseFieldOperation previous) {
if (previous == null) {
Expand Down
11 changes: 10 additions & 1 deletion Parse/src/main/java/com/parse/ParseDeleteOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@
*/
package com.parse;

import android.os.Parcel;

import org.json.JSONException;
import org.json.JSONObject;

/**
* An operation where a field is deleted from the object.
*/
/** package */ class ParseDeleteOperation implements ParseFieldOperation {
/* package */ final static String OP_NAME = "Delete";

private static final ParseDeleteOperation defaultInstance = new ParseDeleteOperation();

public static ParseDeleteOperation getInstance() {
Expand All @@ -27,10 +31,15 @@ private ParseDeleteOperation() {
@Override
public JSONObject encode(ParseEncoder objectEncoder) throws JSONException {
JSONObject output = new JSONObject();
output.put("__op", "Delete");
output.put("__op", OP_NAME);
return output;
}

@Override
public void encode(Parcel dest, ParseParcelEncoder parcelableEncoder) {
dest.writeString(OP_NAME);
}

@Override
public ParseFieldOperation mergeWithPrevious(ParseFieldOperation previous) {
return this;
Expand Down
Loading