Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
blender
monado
Commits
f35ce4ea
Commit
f35ce4ea
authored
Apr 30, 2021
by
Ryan Pavlik
Browse files
external: Update android-jni-wrap
parent
d31bab93
Changes
42
Hide whitespace changes
Inline
Side-by-side
src/external/android-jni-wrap/wrap/android.app.cpp
View file @
f35ce4ea
// Copyright 2020, Collabora, Ltd.
// Copyright 2020
-2021
, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
// Author: Ryan Pavlik <ryan.pavlik@collabora.com>
...
...
src/external/android-jni-wrap/wrap/android.app.h
View file @
f35ce4ea
// Copyright 2020, Collabora, Ltd.
// Copyright 2020
-2021
, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
// Author: Ryan Pavlik <ryan.pavlik@collabora.com>
...
...
@@ -34,7 +34,7 @@ class Service : public content::Context {
* Singleton accessor
*/
static
Meta
&
data
()
{
static
Meta
instance
;
static
Meta
instance
{}
;
return
instance
;
}
...
...
@@ -42,6 +42,7 @@ class Service : public content::Context {
Meta
();
};
};
/*!
* Wrapper for android.app.Activity objects.
*/
...
...
@@ -87,7 +88,7 @@ class Activity : public content::Context {
* Singleton accessor
*/
static
Meta
&
data
()
{
static
Meta
instance
;
static
Meta
instance
{}
;
return
instance
;
}
...
...
@@ -95,6 +96,7 @@ class Activity : public content::Context {
Meta
();
};
};
}
// namespace android::app
}
// namespace wrap
#include "android.app.impl.h"
src/external/android-jni-wrap/wrap/android.app.impl.h
View file @
f35ce4ea
// Copyright 2020, Collabora, Ltd.
// Copyright 2020
-2021
, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
// Author: Ryan Pavlik <ryan.pavlik@collabora.com>
// Inline implementations: do not include on its own!
#pragma once
...
...
@@ -22,5 +23,6 @@ Activity::setVrModeEnabled(bool enabled,
return
object
().
call
<
void
>
(
Meta
::
data
().
setVrModeEnabled
,
enabled
,
requestedComponent
.
object
());
}
}
// namespace android::app
}
// namespace wrap
src/external/android-jni-wrap/wrap/android.content.cpp
View file @
f35ce4ea
// Copyright 2020, Collabora, Ltd.
// Copyright 2020
-2021
, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
// Author: Ryan Pavlik <ryan.pavlik@collabora.com>
...
...
@@ -12,6 +12,8 @@ Context::Meta::Meta(bool deferDrop)
WINDOW_SERVICE
(
classRef
(),
"WINDOW_SERVICE"
),
getPackageManager
(
classRef
().
getMethod
(
"getPackageManager"
,
"()Landroid/content/pm/PackageManager;"
)),
getContentResolver
(
classRef
().
getMethod
(
"getContentResolver"
,
"()Landroid/content/ContentResolver;"
)),
getApplicationContext
(
classRef
().
getMethod
(
"getApplicationContext"
,
"()Landroid/content/Context;"
)),
getClassLoader
(
...
...
@@ -39,7 +41,6 @@ ComponentName::Meta::Meta()
Intent
::
Meta
::
Meta
()
:
MetaBase
(
Intent
::
getTypeName
()),
FLAG_ACTIVITY_NEW_TASK
(
classRef
(),
"FLAG_ACTIVITY_NEW_TASK"
),
init
(
classRef
().
getMethod
(
"<init>"
,
"()V"
)),
init1
(
classRef
().
getMethod
(
"<init>"
,
"(Landroid/content/Intent;)V"
)),
init2
(
classRef
().
getMethod
(
"<init>"
,
"(Ljava/lang/String;)V"
)),
init3
(
classRef
().
getMethod
(
"<init>"
,
...
...
@@ -51,5 +52,21 @@ Intent::Meta::Meta()
"content/Context;Ljava/lang/Class;)V"
)),
setFlags
(
classRef
().
getMethod
(
"setFlags"
,
"(I)Landroid/content/Intent;"
))
{}
ContentResolver
::
Meta
::
Meta
()
:
MetaBaseDroppable
(
ContentResolver
::
getTypeName
()),
query
(
classRef
().
getMethod
(
"query"
,
"(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/"
"String;Ljava/lang/String;)Landroid/database/Cursor;"
)),
query1
(
classRef
().
getMethod
(
"query"
,
"(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/"
"String;[Ljava/lang/String;Ljava/lang/String;Landroid/os/"
"CancellationSignal;)Landroid/database/Cursor;"
)),
query2
(
classRef
().
getMethod
(
"query"
,
"(Landroid/net/Uri;[Ljava/lang/String;Landroid/os/Bundle;Landroid/os/"
"CancellationSignal;)Landroid/database/Cursor;"
))
{
MetaBaseDroppable
::
dropClassRef
();
}
}
// namespace android::content
}
// namespace wrap
src/external/android-jni-wrap/wrap/android.content.h
View file @
f35ce4ea
// Copyright 2020, Collabora, Ltd.
// Copyright 2020
-2021
, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
// Author: Ryan Pavlik <ryan.pavlik@collabora.com>
...
...
@@ -10,6 +10,7 @@
namespace
wrap
{
namespace
android
::
content
{
class
ComponentName
;
class
ContentResolver
;
class
Context
;
class
Intent
;
}
// namespace android::content
...
...
@@ -18,6 +19,10 @@ namespace android::content::pm {
class
PackageManager
;
}
// namespace android::content::pm
namespace
android
::
database
{
class
Cursor
;
}
// namespace android::database
namespace
android
::
os
{
class
Bundle
;
}
// namespace android::os
...
...
@@ -74,6 +79,17 @@ class Context : public ObjectWrapperBase {
*/
pm
::
PackageManager
getPackageManager
();
/*!
* Wrapper for the getContentResolver method
*
* Java prototype:
* `public abstract android.content.ContentResolver getContentResolver();`
*
* JNI signature: ()Landroid/content/ContentResolver;
*
*/
ContentResolver
getContentResolver
()
const
;
/*!
* Wrapper for the getApplicationContext method
*
...
...
@@ -144,6 +160,7 @@ class Context : public ObjectWrapperBase {
impl
::
StaticFieldId
<
std
::
string
>
DISPLAY_SERVICE
;
impl
::
StaticFieldId
<
std
::
string
>
WINDOW_SERVICE
;
jni
::
method_t
getPackageManager
;
jni
::
method_t
getContentResolver
;
jni
::
method_t
getApplicationContext
;
jni
::
method_t
getClassLoader
;
jni
::
method_t
startActivity
;
...
...
@@ -162,6 +179,7 @@ class Context : public ObjectWrapperBase {
explicit
Meta
(
bool
deferDrop
);
};
};
/*!
* Wrapper for android.content.ComponentName objects.
*/
...
...
@@ -183,7 +201,7 @@ class ComponentName : public ObjectWrapperBase {
*
*/
static
ComponentName
construct
(
std
::
string
const
&
pkg
,
std
::
string
const
&
cl
s
);
std
::
string
const
&
cl
assName
);
/*!
* Wrapper for a constructor
...
...
@@ -195,7 +213,8 @@ class ComponentName : public ObjectWrapperBase {
* JNI signature: (Landroid/content/Context;Ljava/lang/String;)V
*
*/
static
ComponentName
construct
(
Context
const
&
pkg
,
std
::
string
const
&
cls
);
static
ComponentName
construct
(
Context
const
&
context
,
std
::
string
const
&
className
);
/*!
* Wrapper for a constructor
...
...
@@ -207,7 +226,7 @@ class ComponentName : public ObjectWrapperBase {
* JNI signature: (Landroid/content/Context;Ljava/lang/Class;)V
*
*/
static
ComponentName
construct
(
Context
const
&
pkg
,
static
ComponentName
construct
(
Context
const
&
context
,
java
::
lang
::
Class
const
&
cls
);
/*!
...
...
@@ -234,7 +253,7 @@ class ComponentName : public ObjectWrapperBase {
* Singleton accessor
*/
static
Meta
&
data
()
{
static
Meta
instance
;
static
Meta
instance
{}
;
return
instance
;
}
...
...
@@ -242,6 +261,7 @@ class ComponentName : public ObjectWrapperBase {
Meta
();
};
};
/*!
* Wrapper for android.content.Intent objects.
*/
...
...
@@ -263,20 +283,6 @@ class Intent : public ObjectWrapperBase {
*/
static
int32_t
FLAG_ACTIVITY_NEW_TASK
();
#if 0
// disabled because of zero-length array warning in jnipp
/*!
* Wrapper for a constructor
*
* Java prototype:
* `public android.content.Intent();`
*
* JNI signature: ()V
*
*/
static Intent construct();
#endif
/*!
* Wrapper for a constructor
*
...
...
@@ -286,7 +292,7 @@ class Intent : public ObjectWrapperBase {
* JNI signature: (Landroid/content/Intent;)V
*
*/
static
Intent
construct
(
Intent
&
intent
);
static
Intent
construct
(
Intent
const
&
intent
);
/*!
* Wrapper for a constructor
...
...
@@ -354,7 +360,6 @@ class Intent : public ObjectWrapperBase {
*/
struct
Meta
:
public
MetaBase
{
impl
::
StaticFieldId
<
int32_t
>
FLAG_ACTIVITY_NEW_TASK
;
jni
::
method_t
init
;
jni
::
method_t
init1
;
jni
::
method_t
init2
;
jni
::
method_t
init3
;
...
...
@@ -366,7 +371,7 @@ class Intent : public ObjectWrapperBase {
* Singleton accessor
*/
static
Meta
&
data
()
{
static
Meta
instance
;
static
Meta
instance
{}
;
return
instance
;
}
...
...
@@ -374,6 +379,91 @@ class Intent : public ObjectWrapperBase {
Meta
();
};
};
/*!
* Wrapper for android.content.ContentResolver objects.
*/
class
ContentResolver
:
public
ObjectWrapperBase
{
public:
using
ObjectWrapperBase
::
ObjectWrapperBase
;
static
constexpr
const
char
*
getTypeName
()
noexcept
{
return
"android/content/ContentResolver"
;
}
/*!
* Wrapper for the query method - overload added in API level 1
*
* Java prototype:
* `public final android.database.Cursor query(android.net.Uri,
* java.lang.String[], java.lang.String, java.lang.String[],
* java.lang.String);`
*
* JNI signature:
* (Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;
*
*/
database
::
Cursor
query
(
jni
::
Object
const
&
uri
,
jni
::
Array
<
std
::
string
>
const
&
projection
,
std
::
string
const
&
selection
,
jni
::
Array
<
std
::
string
>
const
&
selectionArgs
,
std
::
string
const
&
sortOrder
);
/*!
* Wrapper for the query method - overload added in API level 16
*
* Java prototype:
* `public final android.database.Cursor query(android.net.Uri,
* java.lang.String[], java.lang.String, java.lang.String[],
* java.lang.String, android.os.CancellationSignal);`
*
* JNI signature:
* (Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Landroid/os/CancellationSignal;)Landroid/database/Cursor;
*
*/
database
::
Cursor
query
(
jni
::
Object
const
&
uri
,
jni
::
Array
<
std
::
string
>
const
&
projection
,
std
::
string
const
&
selection
,
jni
::
Array
<
std
::
string
>
const
&
selectionArgs
,
std
::
string
const
&
sortOrder
,
jni
::
Object
const
&
cancellationSignal
);
/*!
* Wrapper for the query method - overload added in API level 26
*
* Java prototype:
* `public final android.database.Cursor query(android.net.Uri,
* java.lang.String[], android.os.Bundle, android.os.CancellationSignal);`
*
* JNI signature:
* (Landroid/net/Uri;[Ljava/lang/String;Landroid/os/Bundle;Landroid/os/CancellationSignal;)Landroid/database/Cursor;
*
*/
database
::
Cursor
query
(
jni
::
Object
const
&
uri
,
jni
::
Array
<
std
::
string
>
const
&
projection
,
os
::
Bundle
const
&
queryArgs
,
jni
::
Object
const
&
cancellationSignal
);
/*!
* Class metadata
*/
struct
Meta
:
public
MetaBaseDroppable
{
jni
::
method_t
query
;
jni
::
method_t
query1
;
jni
::
method_t
query2
;
/*!
* Singleton accessor
*/
static
Meta
&
data
()
{
static
Meta
instance
{};
return
instance
;
}
private:
Meta
();
};
};
}
// namespace android::content
}
// namespace wrap
#include "android.content.impl.h"
src/external/android-jni-wrap/wrap/android.content.impl.h
View file @
f35ce4ea
// Copyright 2020, Collabora, Ltd.
// Copyright 2020
-2021
, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
// Author: Ryan Pavlik <ryan.pavlik@collabora.com>
// Inline implementations: do not include on its own!
#pragma once
#include "android.content.pm.h"
#include "android.database.h"
#include "android.os.h"
#include "java.lang.h"
#include <string>
...
...
@@ -12,8 +14,6 @@
namespace
wrap
{
namespace
android
::
content
{
inline
std
::
string
Context
::
DISPLAY_SERVICE
()
{
// Defer dropping the class ref to avoid having to do two class lookups
// by name for this static field. Instead, drop it before we return.
auto
&
data
=
Meta
::
data
(
true
);
auto
ret
=
get
(
data
.
DISPLAY_SERVICE
,
data
.
clazz
());
data
.
dropClassRef
();
...
...
@@ -21,8 +21,6 @@ inline std::string Context::DISPLAY_SERVICE() {
}
inline
std
::
string
Context
::
WINDOW_SERVICE
()
{
// Defer dropping the class ref to avoid having to do two class lookups
// by name for this static field. Instead, drop it before we return.
auto
&
data
=
Meta
::
data
(
true
);
auto
ret
=
get
(
data
.
WINDOW_SERVICE
,
data
.
clazz
());
data
.
dropClassRef
();
...
...
@@ -35,6 +33,12 @@ inline pm::PackageManager Context::getPackageManager() {
object
().
call
<
jni
::
Object
>
(
Meta
::
data
().
getPackageManager
));
}
inline
ContentResolver
Context
::
getContentResolver
()
const
{
assert
(
!
isNull
());
return
ContentResolver
(
object
().
call
<
jni
::
Object
>
(
Meta
::
data
().
getContentResolver
));
}
inline
Context
Context
::
getApplicationContext
()
{
assert
(
!
isNull
());
return
Context
(
...
...
@@ -65,40 +69,35 @@ inline Context Context::createPackageContext(std::string const &packageName,
return
Context
(
object
().
call
<
jni
::
Object
>
(
Meta
::
data
().
createPackageContext
,
packageName
,
flags
));
}
inline
ComponentName
ComponentName
::
construct
(
std
::
string
const
&
pkg
,
std
::
string
const
&
cl
s
)
{
std
::
string
const
&
cl
assName
)
{
return
ComponentName
(
Meta
::
data
().
clazz
().
newInstance
(
Meta
::
data
().
init
,
pkg
,
cl
s
));
Meta
::
data
().
clazz
().
newInstance
(
Meta
::
data
().
init
,
pkg
,
cl
assName
));
}
inline
ComponentName
ComponentName
::
construct
(
Context
const
&
pkg
,
std
::
string
const
&
cl
s
)
{
return
ComponentName
(
Meta
::
data
().
clazz
().
newInstance
(
Meta
::
data
().
init1
,
pkg
.
object
(),
cl
s
));
inline
ComponentName
ComponentName
::
construct
(
Context
const
&
context
,
std
::
string
const
&
cl
assName
)
{
return
ComponentName
(
Meta
::
data
().
clazz
().
newInstance
(
Meta
::
data
().
init1
,
context
.
object
(),
cl
assName
));
}
inline
ComponentName
ComponentName
::
construct
(
Context
const
&
pkg
,
inline
ComponentName
ComponentName
::
construct
(
Context
const
&
context
,
java
::
lang
::
Class
const
&
cls
)
{
return
ComponentName
(
Meta
::
data
().
clazz
().
newInstance
(
Meta
::
data
().
init2
,
pkg
.
object
(),
cls
.
object
()));
Meta
::
data
().
init2
,
context
.
object
(),
cls
.
object
()));
}
inline
ComponentName
ComponentName
::
construct
(
jni
::
Object
const
&
parcel
)
{
return
ComponentName
(
Meta
::
data
().
clazz
().
newInstance
(
Meta
::
data
().
init3
,
parcel
));
}
inline
int32_t
Intent
::
FLAG_ACTIVITY_NEW_TASK
()
{
return
get
(
Meta
::
data
().
FLAG_ACTIVITY_NEW_TASK
,
Meta
::
data
().
clazz
());
}
#if 0
// disabled because of zero-length array warning in jnipp
inline Intent Intent::construct() {
return Intent(Meta::data().clazz().newInstance(Meta::data().init));
}
#endif
inline
Intent
Intent
::
construct
(
Intent
&
intent
)
{
inline
Intent
Intent
::
construct
(
Intent
const
&
intent
)
{
return
Intent
(
Meta
::
data
().
clazz
().
newInstance
(
Meta
::
data
().
init1
,
intent
.
object
()));
}
...
...
@@ -131,5 +130,35 @@ inline Intent Intent::setFlags(int32_t flags) {
assert
(
!
isNull
());
return
Intent
(
object
().
call
<
jni
::
Object
>
(
Meta
::
data
().
setFlags
,
flags
));
}
inline
database
::
Cursor
ContentResolver
::
query
(
jni
::
Object
const
&
uri
,
jni
::
Array
<
std
::
string
>
const
&
projection
,
std
::
string
const
&
selection
,
jni
::
Array
<
std
::
string
>
const
&
selectionArgs
,
std
::
string
const
&
sortOrder
)
{
assert
(
!
isNull
());
return
database
::
Cursor
(
object
().
call
<
jni
::
Object
>
(
Meta
::
data
().
query
,
uri
,
projection
,
selection
,
selectionArgs
,
sortOrder
));
}
inline
database
::
Cursor
ContentResolver
::
query
(
jni
::
Object
const
&
uri
,
jni
::
Array
<
std
::
string
>
const
&
projection
,
std
::
string
const
&
selection
,
jni
::
Array
<
std
::
string
>
const
&
selectionArgs
,
std
::
string
const
&
sortOrder
,
jni
::
Object
const
&
cancellationSignal
)
{
assert
(
!
isNull
());
return
database
::
Cursor
(
object
().
call
<
jni
::
Object
>
(
Meta
::
data
().
query1
,
uri
,
projection
,
selection
,
selectionArgs
,
sortOrder
,
cancellationSignal
));
}
inline
database
::
Cursor
ContentResolver
::
query
(
jni
::
Object
const
&
uri
,
jni
::
Array
<
std
::
string
>
const
&
projection
,
os
::
Bundle
const
&
queryArgs
,
jni
::
Object
const
&
cancellationSignal
)
{
assert
(
!
isNull
());
return
database
::
Cursor
(
object
().
call
<
jni
::
Object
>
(
Meta
::
data
().
query2
,
uri
,
projection
,
queryArgs
.
object
(),
cancellationSignal
));
}
}
// namespace android::content
}
// namespace wrap
src/external/android-jni-wrap/wrap/android.content.pm.cpp
View file @
f35ce4ea
// Copyright 2020, Collabora, Ltd.
// Copyright 2020
-2021
, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
// Author: Ryan Pavlik <ryan.pavlik@collabora.com>
...
...
@@ -40,9 +40,6 @@ PackageManager::Meta::Meta()
getPackageInfo
(
classRef
().
getMethod
(
"getPackageInfo"
,
"(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;"
)),
getPackageInfo1
(
classRef
().
getMethod
(
"getPackageInfo"
,
"(Landroid/content/pm/VersionedPackage;I)Landroid/"
"content/pm/PackageInfo;"
)),
getApplicationInfo
(
classRef
().
getMethod
(
"getApplicationInfo"
,
"(Ljava/lang/String;I)Landroid/content/pm/ApplicationInfo;"
)),
...
...
src/external/android-jni-wrap/wrap/android.content.pm.h
View file @
f35ce4ea
// Copyright 2020, Collabora, Ltd.
// Copyright 2020
-2021
, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
// Author: Ryan Pavlik <ryan.pavlik@collabora.com>
...
...
@@ -86,7 +86,7 @@ class PackageItemInfo : public ObjectWrapperBase {
* Singleton accessor
*/
static
Meta
&
data
()
{
static
Meta
instance
;
static
Meta
instance
{}
;
return
instance
;
}
...
...
@@ -94,6 +94,7 @@ class PackageItemInfo : public ObjectWrapperBase {
Meta
();
};
};
/*!
* Wrapper for android.content.pm.ComponentInfo objects.
*/
...
...
@@ -113,7 +114,7 @@ class ComponentInfo : public PackageItemInfo {
* Singleton accessor
*/
static
Meta
&
data
()
{
static
Meta
instance
;
static
Meta
instance
{}
;
return
instance
;
}
...
...
@@ -121,6 +122,7 @@ class ComponentInfo : public PackageItemInfo {
Meta
();
};
};
/*!
* Wrapper for android.content.pm.ServiceInfo objects.
*/
...
...
@@ -140,7 +142,7 @@ class ServiceInfo : public PackageItemInfo {
* Singleton accessor
*/
static
Meta
&
data
()
{
static
Meta
instance
;
static
Meta
instance
{}
;
return
instance
;
}
...
...
@@ -148,6 +150,7 @@ class ServiceInfo : public PackageItemInfo {
Meta
();
};
};
/*!
* Wrapper for android.content.pm.ApplicationInfo objects.
*/
...
...
@@ -191,7 +194,7 @@ class ApplicationInfo : public PackageItemInfo {
* Singleton accessor
*/
static
Meta
&
data
()
{
static
Meta
instance
;
static
Meta
instance
{}
;
return
instance
;
}
...
...
@@ -199,6 +202,7 @@ class ApplicationInfo : public PackageItemInfo {
Meta
();
};
};
/*!
* Wrapper for android.content.pm.PackageInfo objects.
*/
...
...
@@ -242,7 +246,7 @@ class PackageInfo : public ObjectWrapperBase {
* Singleton accessor
*/
static
Meta
&
data
()
{
static
Meta
instance
;
static
Meta
instance
{}
;
return
instance
;
}
...
...
@@ -250,6 +254,7 @@ class PackageInfo : public ObjectWrapperBase {
Meta
();
};
};
/*!
* Wrapper for android.content.pm.ResolveInfo objects.
*/
...
...
@@ -281,7 +286,7 @@ class ResolveInfo : public ObjectWrapperBase {
* Singleton accessor
*/
static
Meta
&
data
()
{
static
Meta
instance
;
static
Meta
instance
{}
;
return
instance
;
}
...
...
@@ -289,6 +294,7 @@ class ResolveInfo : public ObjectWrapperBase {
Meta
();
};
};
/*!
* Wrapper for android.content.pm.PackageManager objects.
*/
...
...
@@ -312,24 +318,6 @@ class PackageManager : public ObjectWrapperBase {
*/
PackageInfo
getPackageInfo
(
std
::
string
const
&
name
,
int32_t
flags
);
#if 0
// Ambiguous overload until we wrap VersionedPackage
/*!
* Wrapper for the getPackageInfo method
*
* Java prototype:
* `public abstract android.content.pm.PackageInfo
* getPackageInfo(android.content.pm.VersionedPackage, int) throws
* android.content.pm.PackageManager$NameNotFoundException;`
*
* JNI signature:
* (Landroid/content/pm/VersionedPackage;I)Landroid/content/pm/PackageInfo;
*
*/
PackageInfo getPackageInfo(jni::Object &versionedPackage, int32_t flags);
#endif