Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 842a1f4b authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge change 1912 into donut

* changes:
  Hand merge from cupcake_dcm to donut, part 2.
parents 656a2726 841ddefc
Loading
Loading
Loading
Loading
+121 −49
Original line number Diff line number Diff line
@@ -147,7 +147,8 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
    @Override
    public boolean onCreate() {
        if (isTemporary()) throw new IllegalStateException("onCreate() called for temp provider");
        mOpenHelper = new AbstractSyncableContentProvider.DatabaseHelper(getContext(), mDatabaseName);
        mOpenHelper = new AbstractSyncableContentProvider.DatabaseHelper(getContext(),
                mDatabaseName);
        mSyncState = new SyncStateContentProviderHelper(mOpenHelper);

        AccountMonitorListener listener = new AccountMonitorListener() {
@@ -235,76 +236,147 @@ public abstract class AbstractSyncableContentProvider extends SyncableContentPro
        return Collections.emptyList();
    }

    @Override
    public final int update(final Uri url, final ContentValues values,
            final String selection, final String[] selectionArgs) {
    /**
     * <p>
     * Call mOpenHelper.getWritableDatabase() and mDb.beginTransaction().
     * {@link #endTransaction} MUST be called after calling this method.
     * Those methods should be used like this:
     * </p>
     *
     * <pre class="prettyprint">
     * boolean successful = false;
     * beginTransaction();
     * try {
     *     // Do something related to mDb
     *     successful = true;
     *     return ret;
     * } finally {
     *     endTransaction(successful);
     * }
     * </pre>
     *
     * @hide This method is dangerous from the view of database manipulation, though using
     * this makes batch insertion/update/delete much faster.
     */
    public final void beginTransaction() {
        mDb = mOpenHelper.getWritableDatabase();
        mDb.beginTransaction();
    }

    /**
     * <p>
     * Call mDb.endTransaction(). If successful is true, try to call
     * mDb.setTransactionSuccessful() before calling mDb.endTransaction().
     * This method MUST be used with {@link #beginTransaction()}.
     * </p>
     *
     * @hide This method is dangerous from the view of database manipulation, though using
     * this makes batch insertion/update/delete much faster.
     */
    public final void endTransaction(boolean successful) {
        try {
            if (isTemporary() && mSyncState.matches(url)) {
                int numRows = mSyncState.asContentProvider().update(
                        url, values, selection, selectionArgs);
            if (successful) {
                // setTransactionSuccessful() must be called just once during opening the
                // transaction.
                mDb.setTransactionSuccessful();
                return numRows;
            }
        } finally {
            mDb.endTransaction();
        }
    }

            int result = updateInternal(url, values, selection, selectionArgs);
            mDb.setTransactionSuccessful();
    @Override
    public final int update(final Uri uri, final ContentValues values,
            final String selection, final String[] selectionArgs) {
        boolean successful = false;
        beginTransaction();
        try {
            int ret = nonTransactionalUpdate(uri, values, selection, selectionArgs);
            successful = true;
            return  ret;
        } finally {
            endTransaction(successful);
        }
    }

    /**
     * @hide
     */
    public final int nonTransactionalUpdate(final Uri uri, final ContentValues values,
            final String selection, final String[] selectionArgs) {
        if (isTemporary() && mSyncState.matches(uri)) {
            int numRows = mSyncState.asContentProvider().update(
                    uri, values, selection, selectionArgs);
            return numRows;
        }

        int result = updateInternal(uri, values, selection, selectionArgs);
        if (!isTemporary() && result > 0) {
                getContext().getContentResolver().notifyChange(url, null /* observer */,
                        changeRequiresLocalSync(url));
            getContext().getContentResolver().notifyChange(uri, null /* observer */,
                    changeRequiresLocalSync(uri));
        }

        return result;
        } finally {
            mDb.endTransaction();
        }
    }

    @Override
    public final int delete(final Uri url, final String selection,
    public final int delete(final Uri uri, final String selection,
            final String[] selectionArgs) {
        mDb = mOpenHelper.getWritableDatabase();
        mDb.beginTransaction();
        boolean successful = false;
        beginTransaction();
        try {
            if (isTemporary() && mSyncState.matches(url)) {
                int numRows = mSyncState.asContentProvider().delete(url, selection, selectionArgs);
                mDb.setTransactionSuccessful();
            int ret = nonTransactionalDelete(uri, selection, selectionArgs);
            successful = true;
            return ret;
        } finally {
            endTransaction(successful);
        }
    }

    /**
     * @hide
     */
    public final int nonTransactionalDelete(final Uri uri, final String selection,
            final String[] selectionArgs) {
        if (isTemporary() && mSyncState.matches(uri)) {
            int numRows = mSyncState.asContentProvider().delete(uri, selection, selectionArgs);
            return numRows;
        }
            int result = deleteInternal(url, selection, selectionArgs);
            mDb.setTransactionSuccessful();
        int result = deleteInternal(uri, selection, selectionArgs);
        if (!isTemporary() && result > 0) {
                getContext().getContentResolver().notifyChange(url, null /* observer */,
                        changeRequiresLocalSync(url));
            getContext().getContentResolver().notifyChange(uri, null /* observer */,
                    changeRequiresLocalSync(uri));
        }
        return result;
        } finally {
            mDb.endTransaction();
        }
    }

    @Override
    public final Uri insert(final Uri url, final ContentValues values) {
        mDb = mOpenHelper.getWritableDatabase();
        mDb.beginTransaction();
    public final Uri insert(final Uri uri, final ContentValues values) {
        boolean successful = false;
        beginTransaction();
        try {
            if (isTemporary() && mSyncState.matches(url)) {
                Uri result = mSyncState.asContentProvider().insert(url, values);
                mDb.setTransactionSuccessful();
            Uri ret = nonTransactionalInsert(uri, values);
            successful = true;
            return ret;
        } finally {
            endTransaction(successful);
        }
    }

    /**
     * @hide
     */
    public final Uri nonTransactionalInsert(final Uri uri, final ContentValues values) {
        if (isTemporary() && mSyncState.matches(uri)) {
            Uri result = mSyncState.asContentProvider().insert(uri, values);
            return result;
        }
            Uri result = insertInternal(url, values);
            mDb.setTransactionSuccessful();
        Uri result = insertInternal(uri, values);
        if (!isTemporary() && result != null) {
                getContext().getContentResolver().notifyChange(url, null /* observer */,
                        changeRequiresLocalSync(url));
            getContext().getContentResolver().notifyChange(uri, null /* observer */,
                    changeRequiresLocalSync(uri));
        }
        return result;
        } finally {
            mDb.endTransaction();
        }
    }

    @Override
+18 −1
Original line number Diff line number Diff line
@@ -868,6 +868,17 @@ public class Contacts {
        public static final int TYPE_WORK = 2;
        public static final int TYPE_OTHER = 3;

        /**
         * @hide This is temporal. TYPE_MOBILE should be added to TYPE in the future.
         */
        public static final int MOBILE_EMAIL_TYPE_INDEX = 2;

        /**
         * @hide This is temporal. TYPE_MOBILE should be added to TYPE in the future.
         * This is not "mobile" but "CELL" since vCard uses it for identifying mobile phone.
         */
        public static final String MOBILE_EMAIL_TYPE_NAME = "_AUTO_CELL";

        /**
         * The user defined label for the the contact method.
         * <P>Type: TEXT</P>
@@ -1005,9 +1016,15 @@ public class Contacts {
                        }
                    } else {
                        if (!TextUtils.isEmpty(label)) {
                            if (label.toString().equals(MOBILE_EMAIL_TYPE_NAME)) {
                                display =
                                    context.getString(
                                            com.android.internal.R.string.mobileEmailTypeName);
                            } else {
                                display = label;
                            }
                        }
                    }
                    break;
                }

+180 −14
Original line number Diff line number Diff line
@@ -17,12 +17,16 @@
package android.syncml.pim;

import android.content.ContentValues;
import android.util.Log;

import org.apache.commons.codec.binary.Base64;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Map.Entry;
import java.util.regex.Pattern;

public class PropertyNode {

@@ -52,7 +56,9 @@ public class PropertyNode {
    public Set<String> propGroupSet;
    
    public PropertyNode() {
        propName = "";
        propValue = "";
        propValue_vector = new ArrayList<String>();
        paramMap = new ContentValues();
        paramMap_TYPE = new HashSet<String>();
        propGroupSet = new HashSet<String>();
@@ -62,13 +68,21 @@ public class PropertyNode {
            String propName, String propValue, List<String> propValue_vector,
            byte[] propValue_bytes, ContentValues paramMap, Set<String> paramMap_TYPE,
            Set<String> propGroupSet) {
        if (propName != null) {
            this.propName = propName;
        } else {
            this.propName = "";
        }
        if (propValue != null) {
            this.propValue = propValue;
        } else {
            this.propValue = "";
        }
        if (propValue_vector != null) {
            this.propValue_vector = propValue_vector;
        } else {
            this.propValue_vector = new ArrayList<String>();
        }
        this.propValue_bytes = propValue_bytes;
        if (paramMap != null) {
            this.paramMap = paramMap;
@@ -117,17 +131,9 @@ public class PropertyNode {
            // decoded by BASE64 or QUOTED-PRINTABLE. When the size of propValue_vector
            // is 1, the encoded value is stored in propValue, so we do not have to
            // check it.
            if (propValue_vector != null) {
                // Log.d("@@@", "===" + propValue_vector + ", " + node.propValue_vector);
            return (propValue_vector.equals(node.propValue_vector) ||
                        (propValue_vector.size() == 1));
            } else if (node.propValue_vector != null) {
                // Log.d("@@@", "===" + propValue_vector + ", " + node.propValue_vector);
                return (node.propValue_vector.equals(propValue_vector) ||
                        (node.propValue_vector.size() == 1));
            } else {
                return true;
            }
                    propValue_vector.size() == 1 ||
                    node.propValue_vector.size() == 1);
        }
    }
    
@@ -154,4 +160,164 @@ public class PropertyNode {
        builder.append(propValue);
        return builder.toString();
    }
    
    /**
     * Encode this object into a string which can be decoded. 
     */
    public String encode() {
        // PropertyNode#toString() is for reading, not for parsing in the future.
        // We construct appropriate String here.
        StringBuilder builder = new StringBuilder();
        if (propName.length() > 0) {
            builder.append("propName:[");
            builder.append(propName);
            builder.append("],");
        }
        int size = propGroupSet.size();
        if (size > 0) {
            Set<String> set = propGroupSet;
            builder.append("propGroup:[");
            int i = 0;
            for (String group : set) {
                // We do not need to double quote groups.
                // group        = 1*(ALPHA / DIGIT / "-")
                builder.append(group);
                if (i < size - 1) {
                    builder.append(",");
                }
                i++;
            }
            builder.append("],");
        }

        if (paramMap.size() > 0 || paramMap_TYPE.size() > 0) {
            ContentValues values = paramMap;
            builder.append("paramMap:[");
            size = paramMap.size(); 
            int i = 0;
            for (Entry<String, Object> entry : values.valueSet()) {
                // Assuming param-key does not contain NON-ASCII nor symbols.
                //
                // According to vCard 3.0:
                // param-name   = iana-token / x-name
                builder.append(entry.getKey());

                // param-value may contain any value including NON-ASCIIs.
                // We use the following replacing rule.
                // \ -> \\
                // , -> \,
                // In String#replaceAll(), "\\\\" means a single backslash.
                builder.append("=");
                builder.append(entry.getValue().toString()
                        .replaceAll("\\\\", "\\\\\\\\")
                        .replaceAll(",", "\\\\,"));
                if (i < size -1) {
                    builder.append(",");
                }
                i++;
            }

            Set<String> set = paramMap_TYPE;
            size = paramMap_TYPE.size();
            if (i > 0 && size > 0) {
                builder.append(",");
            }
            i = 0;
            for (String type : set) {
                builder.append("TYPE=");
                builder.append(type
                        .replaceAll("\\\\", "\\\\\\\\")
                        .replaceAll(",", "\\\\,"));
                if (i < size - 1) {
                    builder.append(",");
                }
                i++;
            }
            builder.append("],");
        }

        size = propValue_vector.size();
        if (size > 0) {
            builder.append("propValue:[");
            List<String> list = propValue_vector;
            for (int i = 0; i < size; i++) {
                builder.append(list.get(i)
                        .replaceAll("\\\\", "\\\\\\\\")
                        .replaceAll(",", "\\\\,"));
                if (i < size -1) {
                    builder.append(",");
                }
            }
            builder.append("],");
        }

        return builder.toString();
    }

    public static PropertyNode decode(String encodedString) {
        PropertyNode propertyNode = new PropertyNode();
        String trimed = encodedString.trim();
        if (trimed.length() == 0) {
            return propertyNode;
        }
        String[] elems = trimed.split("],");
        
        for (String elem : elems) {
            int index = elem.indexOf('[');
            String name = elem.substring(0, index - 1);
            Pattern pattern = Pattern.compile("(?<!\\\\),");
            String[] values = pattern.split(elem.substring(index + 1), -1);
            if (name.equals("propName")) {
                propertyNode.propName = values[0];
            } else if (name.equals("propGroupSet")) {
                for (String value : values) {
                    propertyNode.propGroupSet.add(value);
                }
            } else if (name.equals("paramMap")) {
                ContentValues paramMap = propertyNode.paramMap;
                Set<String> paramMap_TYPE = propertyNode.paramMap_TYPE;
                for (String value : values) {
                    String[] tmp = value.split("=", 2);
                    String mapKey = tmp[0];
                    // \, -> ,
                    // \\ -> \
                    // In String#replaceAll(), "\\\\" means a single backslash.
                    String mapValue =
                        tmp[1].replaceAll("\\\\,", ",").replaceAll("\\\\\\\\", "\\\\");
                    if (mapKey.equalsIgnoreCase("TYPE")) {
                        paramMap_TYPE.add(mapValue);
                    } else {
                        paramMap.put(mapKey, mapValue);
                    }
                }
            } else if (name.equals("propValue")) {
                StringBuilder builder = new StringBuilder();
                List<String> list = propertyNode.propValue_vector;
                int length = values.length;
                for (int i = 0; i < length; i++) {
                    String normValue = values[i]
                                              .replaceAll("\\\\,", ",")
                                              .replaceAll("\\\\\\\\", "\\\\");
                    list.add(normValue);
                    builder.append(normValue);
                    if (i < length - 1) {
                        builder.append(";");
                    }
                }
                propertyNode.propValue = builder.toString();
            }
        }
        
        // At this time, QUOTED-PRINTABLE is already decoded to Java String.
        // We just need to decode BASE64 String to binary.
        String encoding = propertyNode.paramMap.getAsString("ENCODING");
        if (encoding != null &&
                (encoding.equalsIgnoreCase("BASE64") ||
                        encoding.equalsIgnoreCase("B"))) {
            propertyNode.propValue_bytes =
                Base64.decodeBase64(propertyNode.propValue_vector.get(0).getBytes());
        }
        
        return propertyNode;
    }
}
+100 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * 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 android.syncml.pim;

import java.util.Collection;
import java.util.List;

public class VBuilderCollection implements VBuilder {

    private final Collection<VBuilder> mVBuilderCollection;
    
    public VBuilderCollection(Collection<VBuilder> vBuilderCollection) {
        mVBuilderCollection = vBuilderCollection; 
    }
    
    public Collection<VBuilder> getVBuilderCollection() {
        return mVBuilderCollection;
    }
    
    public void start() {
        for (VBuilder builder : mVBuilderCollection) {
            builder.start();
        }
    }
    
    public void end() {
        for (VBuilder builder : mVBuilderCollection) {
            builder.end();
        }
    }

    public void startRecord(String type) {
        for (VBuilder builder : mVBuilderCollection) {
            builder.startRecord(type);
        }
    }
    
    public void endRecord() {
        for (VBuilder builder : mVBuilderCollection) {
            builder.endRecord();
        }
    }

    public void startProperty() {
        for (VBuilder builder : mVBuilderCollection) {
            builder.startProperty();
        }
    }

    
    public void endProperty() {
        for (VBuilder builder : mVBuilderCollection) {
            builder.endProperty();
        }
    }

    public void propertyGroup(String group) {
        for (VBuilder builder : mVBuilderCollection) {
            builder.propertyGroup(group);
        }
    }

    public void propertyName(String name) {
        for (VBuilder builder : mVBuilderCollection) {
            builder.propertyName(name);
        }
    }

    public void propertyParamType(String type) {
        for (VBuilder builder : mVBuilderCollection) {
            builder.propertyParamType(type);
        }
    }

    public void propertyParamValue(String value) {
        for (VBuilder builder : mVBuilderCollection) {
            builder.propertyParamValue(value);
        }
    }

    public void propertyValues(List<String> values) {
        for (VBuilder builder : mVBuilderCollection) {
            builder.propertyValues(values);
        }
    }
}
+172 −121

File changed.

Preview size limit exceeded, changes collapsed.

Loading