TestArgsContentProvider.java

/*
 * Copyright (C) 2019 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 androidx.test.services.storage.provider;

import static androidx.test.internal.util.Checks.checkNotNull;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import androidx.test.services.storage.TestStorageConstants;
import androidx.test.services.storage.TestStorageServiceProto.TestArgument;
import androidx.test.services.storage.TestStorageServiceProto.TestArguments;
import androidx.test.services.storage.file.HostedFile;
import androidx.test.services.storage.file.PropertyFile;
import androidx.test.services.storage.file.PropertyFile.Authority;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

/**
 * Provides access to test arguments stored as a file on external device storage. This provider
 * supports only the query api. Use {@link PropertyFile#buildUri(Authority)} to retrieve all test
 * arguments. To retrieve a specific argument, build the URI with the arg name as path by calling
 * {@link PropertyFile#buildUri(Authority, String)}.
 */
@SuppressWarnings("javadoc")
public final class TestArgsContentProvider extends ContentProvider {

  private static final String TAG = "TestArgCP";
  private static final String ANDROID_TEST_SERVER_SPEC_FORMAT = "_server_address";

  private static final String SYSTEM_PROPERTY_CLAZZ = "android.os.SystemProperties";
  private static final String GET_METHOD = "get";

  private String systemPropertyClassName;
  private Method getString;

  void setSystemPropertyClassNameForTest(String className) {
    this.systemPropertyClassName = className;
  }

  @Override
  public int delete(Uri arg0, String arg1, String[] arg2) {
    // Not allowed.
    return 0;
  }

  @Override
  public String getType(Uri arg0) {
    // mime types not supported
    return null;
  }

  @Override
  public Uri insert(Uri arg0, ContentValues arg1) {
    throw new UnsupportedOperationException("Insertion is not allowed.");
  }

  @Override
  public boolean onCreate() {
    return true;
  }

  @Override
  public Cursor query(
      Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    checkNotNull(uri);

    Map<String, String> argMap = buildArgMapFromFile();

    MatrixCursor cursor = new MatrixCursor(PropertyFile.Column.getNames());
    String argName = uri.getLastPathSegment();
    if (argName != null) {
      // Return the specific arg name/value.
      if (argMap.containsKey(argName)) {
        String[] row = {argName, argMap.get(argName)};
        cursor.addRow(row);
      }
    } else {
      // No specific arg specified. Return the entire argMap.
      for (Entry<String, String> entry : argMap.entrySet()) {
        String[] row = {entry.getKey(), entry.getValue()};
        cursor.addRow(row);
      }
    }
    return cursor;
  }

  private Map<String, String> buildArgMapFromFile() {
    Map<String, String> argMap = new HashMap<>();

    for (TestArgument testArg : readProtoFromFile().getArgList()) {
      String key = testArg.getName();
      String val = testArg.getValue();
      argMap.put(key, val);
    }
    return argMap;
  }

  private static TestArguments readProtoFromFile() {
    File testArgsFile =
        new File(
            HostedFile.getRootDirectory(),
            TestStorageConstants.ON_DEVICE_PATH_INTERNAL_USE
                + TestStorageConstants.TEST_ARGS_FILE_NAME);
    if (!testArgsFile.exists()) {
      return TestArguments.getDefaultInstance();
    }
    try {
      return TestArguments.parseFrom(new FileInputStream(testArgsFile));
    } catch (IOException e) {
      throw new RuntimeException("Not able to read from file: " + testArgsFile.getName(), e);
    }
  }

  @Override
  public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
    // Not allowed.
    return 0;
  }
}