summary refs log tree commit diff
diff options
context:
space:
mode:
authorArtturi <Artturin@artturin.com>2023-03-03 17:05:04 +0200
committerGitHub <noreply@github.com>2023-03-03 17:05:04 +0200
commit117fc28b9883ab7a7bcbc2762f9ed8a55458a338 (patch)
tree567a52524d476e677929b6444fcf8cb1fbd8ee8a
parentb1da477808a99a9b70fa02e692e24bd2b5d47948 (diff)
parenta05928d7fed88bea451eb865a122197a4aed4e3a (diff)
downloadnixpkgs-117fc28b9883ab7a7bcbc2762f9ed8a55458a338.tar
nixpkgs-117fc28b9883ab7a7bcbc2762f9ed8a55458a338.tar.gz
nixpkgs-117fc28b9883ab7a7bcbc2762f9ed8a55458a338.tar.bz2
nixpkgs-117fc28b9883ab7a7bcbc2762f9ed8a55458a338.tar.lz
nixpkgs-117fc28b9883ab7a7bcbc2762f9ed8a55458a338.tar.xz
nixpkgs-117fc28b9883ab7a7bcbc2762f9ed8a55458a338.tar.zst
nixpkgs-117fc28b9883ab7a7bcbc2762f9ed8a55458a338.zip
Merge pull request #213871 from hadilq/androidenv/fix-create-avd
-rw-r--r--pkgs/development/mobile/androidenv/.gitignore1
-rw-r--r--pkgs/development/mobile/androidenv/compose-android-packages.nix52
-rw-r--r--pkgs/development/mobile/androidenv/default.nix2
-rw-r--r--pkgs/development/mobile/androidenv/emulate-app.nix68
-rw-r--r--pkgs/development/mobile/androidenv/examples/shell-with-emulator.nix151
-rw-r--r--pkgs/development/mobile/androidenv/examples/shell.nix14
-rw-r--r--pkgs/development/mobile/androidenv/test-suite.nix15
7 files changed, 257 insertions, 46 deletions
diff --git a/pkgs/development/mobile/androidenv/.gitignore b/pkgs/development/mobile/androidenv/.gitignore
index c15750760a4..2a297b88cde 100644
--- a/pkgs/development/mobile/androidenv/.gitignore
+++ b/pkgs/development/mobile/androidenv/.gitignore
@@ -1,2 +1,3 @@
 /xml
 local.properties
+.android
diff --git a/pkgs/development/mobile/androidenv/compose-android-packages.nix b/pkgs/development/mobile/androidenv/compose-android-packages.nix
index d27c1bb1cdc..8c24b10093b 100644
--- a/pkgs/development/mobile/androidenv/compose-android-packages.nix
+++ b/pkgs/development/mobile/androidenv/compose-android-packages.nix
@@ -185,20 +185,38 @@ rec {
 
   system-images = lib.flatten (map (apiVersion:
     map (type:
-      map (abiVersion:
-        lib.optionals (lib.hasAttrByPath [apiVersion type abiVersion] system-images-packages) (
-          deployAndroidPackage {
-            inherit os;
-            package = system-images-packages.${apiVersion}.${type}.${abiVersion};
-            # Patch 'google_apis' system images so they're recognized by the sdk.
-            # Without this, `android list targets` shows 'Tag/ABIs : no ABIs' instead
-            # of 'Tag/ABIs : google_apis*/*' and the emulator fails with an ABI-related error.
-            patchInstructions = lib.optionalString (lib.hasPrefix "google_apis" type) ''
+      # Deploy all system images with the same  systemImageType in one derivation to avoid the `null` problem below
+      # with avdmanager when trying to create an avd!
+      #
+      # ```
+      # $ yes "" | avdmanager create avd --force --name testAVD --package 'system-images;android-33;google_apis;x86_64'
+      # Error: Package path is not valid. Valid system image paths are:
+      # null
+      # ```
+      let
+        availablePackages = map (abiVersion:
+          system-images-packages.${apiVersion}.${type}.${abiVersion}
+        ) (builtins.filter (abiVersion:
+          lib.hasAttrByPath [apiVersion type abiVersion] system-images-packages
+        ) abiVersions);
+
+        instructions = builtins.listToAttrs (map (package: {
+            name = package.name;
+            value = lib.optionalString (lib.hasPrefix "google_apis" type) ''
+              # Patch 'google_apis' system images so they're recognized by the sdk.
+              # Without this, `android list targets` shows 'Tag/ABIs : no ABIs' instead
+              # of 'Tag/ABIs : google_apis*/*' and the emulator fails with an ABI-related error.
               sed -i '/^Addon.Vendor/d' source.properties
             '';
-          }
-        )
-      ) abiVersions
+          }) availablePackages
+        );
+      in
+      lib.optionals (availablePackages != [])
+        (deployAndroidPackages {
+          inherit os;
+          packages = availablePackages;
+          patchesInstructions = instructions;
+        })
     ) systemImageTypes
   ) platformVersions);
 
@@ -271,8 +289,8 @@ rec {
     ${lib.concatMapStrings (system-image: ''
       apiVersion=$(basename $(echo ${system-image}/libexec/android-sdk/system-images/*))
       type=$(basename $(echo ${system-image}/libexec/android-sdk/system-images/*/*))
-      mkdir -p system-images/$apiVersion/$type
-      ln -s ${system-image}/libexec/android-sdk/system-images/$apiVersion/$type/* system-images/$apiVersion/$type
+      mkdir -p system-images/$apiVersion
+      ln -s ${system-image}/libexec/android-sdk/system-images/$apiVersion/$type system-images/$apiVersion/$type
     '') images}
   '';
 
@@ -294,7 +312,11 @@ rec {
     You must accept the following licenses:
     ${lib.concatMapStringsSep "\n" (str: "  - ${str}") licenseNames}
 
-    by setting nixpkgs config option 'android_sdk.accept_license = true;'.
+    a)
+      by setting nixpkgs config option 'android_sdk.accept_license = true;'.
+    b)
+      by an environment variable for a single invocation of the nix tools.
+        $ export NIXPKGS_ACCEPT_ANDROID_SDK_LICENSE=1
   '' else callPackage ./cmdline-tools.nix {
     inherit deployAndroidPackage os cmdLineToolsVersion;
 
diff --git a/pkgs/development/mobile/androidenv/default.nix b/pkgs/development/mobile/androidenv/default.nix
index 9bd9fb9a543..3de6bf6e478 100644
--- a/pkgs/development/mobile/androidenv/default.nix
+++ b/pkgs/development/mobile/androidenv/default.nix
@@ -1,5 +1,5 @@
 { config, pkgs ? import <nixpkgs> {}
-, licenseAccepted ? config.android_sdk.accept_license or false
+, licenseAccepted ? config.android_sdk.accept_license or (builtins.getEnv "NIXPKGS_ACCEPT_ANDROID_SDK_LICENSE" == "1")
 }:
 
 rec {
diff --git a/pkgs/development/mobile/androidenv/emulate-app.nix b/pkgs/development/mobile/androidenv/emulate-app.nix
index ef803779ad6..e4a9615e4f7 100644
--- a/pkgs/development/mobile/androidenv/emulate-app.nix
+++ b/pkgs/development/mobile/androidenv/emulate-app.nix
@@ -1,20 +1,30 @@
 { composeAndroidPackages, stdenv, lib, runtimeShell }:
 { name, app ? null
-, platformVersion ? "16", abiVersion ? "armeabi-v7a", systemImageType ? "default"
-, enableGPU ? false, extraAVDFiles ? []
-, package ? null, activity ? null
-, avdHomeDir ? null, sdkExtraArgs ? {}
+, platformVersion ? "33"
+, abiVersion ? "armeabi-v7a"
+, systemImageType ? "default"
+, enableGPU ? false
+, extraAVDFiles ? []
+, package ? null
+, activity ? null
+, androidUserHome ? null
+, avdHomeDir ? null # Support old variable with non-standard naming!
+, androidAvdHome ? avdHomeDir
+, sdkExtraArgs ? {}
+, androidAvdFlags ? null
+, androidEmulatorFlags ? null
 }:
 
 let
   sdkArgs = {
-    toolsVersion = "26.1.1";
-    platformVersions = [ platformVersion ];
     includeEmulator = true;
     includeSystemImages = true;
+  } // sdkExtraArgs // {
+    cmdLineToolsVersion = "8.0";
+    platformVersions = [ platformVersion ];
     systemImageTypes = [ systemImageType ];
     abiVersions = [ abiVersion ];
-  } // sdkExtraArgs;
+  };
 
   sdk = (composeAndroidPackages sdkArgs).androidsdk;
 in
@@ -33,24 +43,45 @@ stdenv.mkDerivation {
         export TMPDIR=/tmp
     fi
 
-    ${if avdHomeDir == null then ''
+    ${if androidUserHome == null then ''
       # Store the virtual devices somewhere else, instead of polluting a user's HOME directory
-      export ANDROID_SDK_HOME=$(mktemp -d $TMPDIR/nix-android-vm-XXXX)
+      export ANDROID_USER_HOME=$(mktemp -d $TMPDIR/nix-android-user-home-XXXX)
+    '' else ''
+      mkdir -p "${androidUserHome}"
+      export ANDROID_USER_HOME="${androidUserHome}"
+    ''}
+
+    ${if androidAvdHome == null then ''
+      export ANDROID_AVD_HOME=$ANDROID_USER_HOME/avd
     '' else ''
-      mkdir -p "${avdHomeDir}"
-      export ANDROID_SDK_HOME="${avdHomeDir}"
+      mkdir -p "${androidAvdHome}"
+      export ANDROID_AVD_HOME="${androidAvdHome}"
     ''}
 
     # We need to specify the location of the Android SDK root folder
     export ANDROID_SDK_ROOT=${sdk}/libexec/android-sdk
 
+    ${lib.optionalString (androidAvdFlags != null) ''
+      # If NIX_ANDROID_AVD_FLAGS is empty
+      if [[ -z "$NIX_ANDROID_AVD_FLAGS" ]]; then
+        NIX_ANDROID_AVD_FLAGS="${androidAvdFlags}"
+      fi
+    ''}
+
+    ${lib.optionalString (androidEmulatorFlags != null) ''
+      # If NIX_ANDROID_EMULATOR_FLAGS is empty
+      if [[ -z "$NIX_ANDROID_EMULATOR_FLAGS" ]]; then
+        NIX_ANDROID_EMULATOR_FLAGS="${androidEmulatorFlags}"
+      fi
+    ''}
+
     # We have to look for a free TCP port
 
     echo "Looking for a free TCP port in range 5554-5584" >&2
 
     for i in $(seq 5554 2 5584)
     do
-        if [ -z "$(${sdk}/libexec/android-sdk/platform-tools/adb devices | grep emulator-$i)" ]
+        if [ -z "$(${sdk}/bin/adb devices | grep emulator-$i)" ]
         then
             port=$i
             break
@@ -68,25 +99,26 @@ stdenv.mkDerivation {
     export ANDROID_SERIAL="emulator-$port"
 
     # Create a virtual android device for testing if it does not exist
-    ${sdk}/libexec/android-sdk/tools/bin/avdmanager list target
+    ${sdk}/bin/avdmanager list target
 
-    if [ "$(${sdk}/libexec/android-sdk/tools/android list avd | grep 'Name: device')" = "" ]
+    if [ "$(${sdk}/bin/avdmanager list avd | grep 'Name: device')" = "" ]
     then
         # Create a virtual android device
-        yes "" | ${sdk}/libexec/android-sdk/tools/bin/avdmanager create avd -n device -k "system-images;android-${platformVersion};${systemImageType};${abiVersion}" $NIX_ANDROID_AVD_FLAGS
+        yes "" | ${sdk}/bin/avdmanager create avd --force -n device -k "system-images;android-${platformVersion};${systemImageType};${abiVersion}" -p $ANDROID_AVD_HOME $NIX_ANDROID_AVD_FLAGS
 
         ${lib.optionalString enableGPU ''
           # Enable GPU acceleration
-          echo "hw.gpu.enabled=yes" >> $ANDROID_SDK_HOME/.android/avd/device.avd/config.ini
+          echo "hw.gpu.enabled=yes" >> $ANDROID_AVD_HOME/device.avd/config.ini
         ''}
 
         ${lib.concatMapStrings (extraAVDFile: ''
-          ln -sf ${extraAVDFile} $ANDROID_SDK_HOME/.android/avd/device.avd
+          ln -sf ${extraAVDFile} $ANDROID_AVD_HOME/device.avd
         '') extraAVDFiles}
     fi
 
     # Launch the emulator
-    ${sdk}/libexec/android-sdk/emulator/emulator -avd device -no-boot-anim -port $port $NIX_ANDROID_EMULATOR_FLAGS &
+    echo "\nLaunch the emulator"
+    $ANDROID_SDK_ROOT/emulator/emulator -avd device -no-boot-anim -port $port $NIX_ANDROID_EMULATOR_FLAGS &
 
     # Wait until the device has completely booted
     echo "Waiting until the emulator has booted the device and the package manager is ready..." >&2
diff --git a/pkgs/development/mobile/androidenv/examples/shell-with-emulator.nix b/pkgs/development/mobile/androidenv/examples/shell-with-emulator.nix
new file mode 100644
index 00000000000..ebfe97b856a
--- /dev/null
+++ b/pkgs/development/mobile/androidenv/examples/shell-with-emulator.nix
@@ -0,0 +1,151 @@
+{
+  # To test your changes in androidEnv run `nix-shell android-sdk-with-emulator-shell.nix`
+
+  # If you copy this example out of nixpkgs, use these lines instead of the next.
+  # This example pins nixpkgs: https://nix.dev/tutorials/towards-reproducibility-pinning-nixpkgs.html
+  /*nixpkgsSource ? (builtins.fetchTarball {
+    name = "nixpkgs-20.09";
+    url = "https://github.com/NixOS/nixpkgs/archive/20.09.tar.gz";
+    sha256 = "1wg61h4gndm3vcprdcg7rc4s1v3jkm5xd7lw8r2f67w502y94gcy";
+  }),
+  pkgs ? import nixpkgsSource {
+    config.allowUnfree = true;
+  },
+  */
+
+  # If you want to use the in-tree version of nixpkgs:
+  pkgs ? import ../../../../.. {
+    config.allowUnfree = true;
+  },
+
+  config ? pkgs.config
+}:
+
+# Copy this file to your Android project.
+let
+  # Declaration of versions for everything. This is useful since these
+  # versions may be used in multiple places in this Nix expression.
+  android = {
+    platforms = [ "33" ];
+    systemImageTypes = [ "google_apis" ];
+    abis = [ "arm64-v8a" "x86_64" ];
+  };
+
+  # If you copy this example out of nixpkgs, something like this will work:
+  /*androidEnvNixpkgs = fetchTarball {
+    name = "androidenv";
+    url = "https://github.com/NixOS/nixpkgs/archive/<fill me in from Git>.tar.gz";
+    sha256 = "<fill me in with nix-prefetch-url --unpack>";
+  };
+
+  androidEnv = pkgs.callPackage "${androidEnvNixpkgs}/pkgs/development/mobile/androidenv" {
+    inherit config pkgs;
+    licenseAccepted = true;
+  };*/
+
+  # Otherwise, just use the in-tree androidenv:
+  androidEnv = pkgs.callPackage ./.. {
+    inherit config pkgs;
+    # You probably need to uncomment below line to express consent.
+    # licenseAccepted = true;
+  };
+
+  sdkArgs = {
+    platformVersions = android.platforms;
+    abiVersions = android.abis;
+    systemImageTypes = android.systemImageTypes;
+
+    includeSystemImages = true;
+    includeEmulator = true;
+
+    # Accepting more licenses declaratively:
+    extraLicenses = [
+      # Already accepted for you with the global accept_license = true or
+      # licenseAccepted = true on androidenv.
+      # "android-sdk-license"
+
+      # These aren't, but are useful for more uncommon setups.
+      "android-sdk-preview-license"
+      "android-googletv-license"
+      "android-sdk-arm-dbt-license"
+      "google-gdk-license"
+      "intel-android-extra-license"
+      "intel-android-sysimage-license"
+      "mips-android-sysimage-license"
+    ];
+  };
+
+  androidComposition = androidEnv.composeAndroidPackages sdkArgs;
+  androidEmulator = androidEnv.emulateApp {
+    name = "android-sdk-emulator-demo";
+    sdkExtraArgs = sdkArgs;
+  };
+  androidSdk = androidComposition.androidsdk;
+  platformTools = androidComposition.platform-tools;
+  jdk = pkgs.jdk;
+in
+pkgs.mkShell rec {
+  name = "androidenv-demo";
+  packages = [ androidSdk platformTools androidEmulator jdk pkgs.android-studio ];
+
+  LANG = "C.UTF-8";
+  LC_ALL = "C.UTF-8";
+  JAVA_HOME = jdk.home;
+
+  # Note: ANDROID_HOME is deprecated. Use ANDROID_SDK_ROOT.
+  ANDROID_SDK_ROOT = "${androidSdk}/libexec/android-sdk";
+  ANDROID_NDK_ROOT = "${ANDROID_SDK_ROOT}/ndk-bundle";
+
+  shellHook = ''
+    # Write out local.properties for Android Studio.
+    cat <<EOF > local.properties
+    # This file was automatically generated by nix-shell.
+    sdk.dir=$ANDROID_SDK_ROOT
+    ndk.dir=$ANDROID_NDK_ROOT
+    EOF
+  '';
+
+  passthru.tests = {
+
+    shell-with-emulator-sdkmanager-packages-test = pkgs.runCommand "shell-with-emulator-sdkmanager-packages-test" {
+      nativeBuildInputs = [ androidSdk jdk ];
+    } ''
+      output="$(sdkmanager --list)"
+      installed_packages_section=$(echo "''${output%%Available Packages*}" | awk 'NR>4 {print $1}')
+      echo "installed_packages_section: ''${installed_packages_section}"
+
+      packages=(
+        "build-tools;33.0.1" "cmdline-tools;8.0" \
+        "emulator" "patcher;v4" "platform-tools" "platforms;android-33" \
+        "system-images;android-33;google_apis;arm64-v8a" \
+        "system-images;android-33;google_apis;x86_64"
+      )
+
+      for package in "''${packages[@]}"; do
+        if [[ ! $installed_packages_section =~ "$package" ]]; then
+          echo "$package package was not installed."
+          exit 1
+        fi
+      done
+
+      touch "$out"
+    '';
+
+    shell-with-emulator-avdmanager-create-avd-test = pkgs.runCommand "shell-with-emulator-avdmanager-create-avd-test" {
+      nativeBuildInputs = [ androidSdk androidEmulator jdk ];
+    } ''
+      avdmanager delete avd -n testAVD || true
+      echo "" | avdmanager create avd --force --name testAVD --package 'system-images;android-33;google_apis;x86_64'
+      result=$(avdmanager list avd)
+
+      if [[ ! $result =~ "Name: testAVD" ]]; then
+        echo "avdmanager couldn't create the avd! The output is :''${result}"
+        exit 1
+      fi
+
+      avdmanager delete avd -n testAVD || true
+      touch "$out"
+    '';
+  };
+}
+
diff --git a/pkgs/development/mobile/androidenv/examples/shell.nix b/pkgs/development/mobile/androidenv/examples/shell.nix
index 8c51ba09e53..775f69bce4c 100644
--- a/pkgs/development/mobile/androidenv/examples/shell.nix
+++ b/pkgs/development/mobile/androidenv/examples/shell.nix
@@ -56,7 +56,8 @@ let
   # Otherwise, just use the in-tree androidenv:
   androidEnv = pkgs.callPackage ./.. {
     inherit config pkgs;
-    licenseAccepted = true;
+    # You probably need to uncomment below line to express consent.
+    # licenseAccepted = true;
   };
 
   androidComposition = androidEnv.composeAndroidPackages {
@@ -146,8 +147,9 @@ pkgs.mkShell rec {
   '';
 
   passthru.tests = {
-    sdkmanager-licenses-test = pkgs.runCommand "sdkmanager-licenses-test" {
-      buildInputs = [ androidSdk jdk ];
+
+    shell-sdkmanager-licenses-test = pkgs.runCommand "shell-sdkmanager-licenses-test" {
+      nativeBuildInputs = [ androidSdk jdk ];
     } ''
       if [[ ! "$(sdkmanager --licenses)" =~ "All SDK package licenses accepted." ]]; then
         echo "At least one of SDK package licenses are not accepted."
@@ -156,14 +158,14 @@ pkgs.mkShell rec {
       touch $out
     '';
 
-    sdkmanager-packages-test = pkgs.runCommand "sdkmanager-packages-test" {
-      buildInputs = [ androidSdk jdk ];
+    shell-sdkmanager-packages-test = pkgs.runCommand "shell-sdkmanager-packages-test" {
+      nativeBuildInputs = [ androidSdk jdk ];
     } ''
       output="$(sdkmanager --list)"
       installed_packages_section=$(echo "''${output%%Available Packages*}" | awk 'NR>4 {print $1}')
 
       packages=(
-        "build-tools;30.0.3" "ndk-bundle" "platform-tools" \
+        "build-tools;30.0.3" "platform-tools" \
         "platforms;android-23" "platforms;android-24" "platforms;android-25" "platforms;android-26" \
         "platforms;android-27" "platforms;android-28" "platforms;android-29" "platforms;android-30" \
         "platforms;android-31" "platforms;android-32" "platforms;android-33" \
diff --git a/pkgs/development/mobile/androidenv/test-suite.nix b/pkgs/development/mobile/androidenv/test-suite.nix
index d063b73ccb4..b5aeca43246 100644
--- a/pkgs/development/mobile/androidenv/test-suite.nix
+++ b/pkgs/development/mobile/androidenv/test-suite.nix
@@ -1,16 +1,19 @@
-{ stdenv, callPackage }:
+{callPackage, lib, stdenv}:
 let
   examples-shell = callPackage ./examples/shell.nix {};
+  examples-shell-with-emulator = callPackage ./examples/shell-with-emulator.nix {};
+  all-tests = examples-shell.passthru.tests //
+    examples-shell-with-emulator.passthru.tests;
 in
 stdenv.mkDerivation {
   name = "androidenv-test-suite";
+  buidInputs = lib.mapAttrsToList (name: value: value) all-tests;
 
-  src = ./.;
+  buildCommand = ''
+    touch $out
+  '';
 
-  dontConfigure = true;
-  dontBuild = true;
-
-  passthru.tests = { } // examples-shell.passthru.tests;
+  passthru.tests = all-tests;
 
   meta.timeout = 60;
 }